/cron-scheduler
Schedule management with staggering, quiet hours, and wake-up override. Validates schedules, prevents collisions, and gates delivery during quiet hours.
Claude Code
$ npx -y skills add garrytan/gbrain --skill cron-scheduler --agent claude-code
Codex
$ npx skills add garrytan/gbrain --skill cron-scheduler -a codex -y
Cursor
$ npx skills add garrytan/gbrain --skill cron-scheduler -a cursor -y
Gemini CLI
$ npx skills add garrytan/gbrain --skill cron-scheduler -a gemini-cli -y
GitHub Copilot
$ npx skills add garrytan/gbrain --skill cron-scheduler -a github-copilot -y
OpenCode
$ npx skills add garrytan/gbrain --skill cron-scheduler -a opencode -y
Windsurf
$ npx skills add garrytan/gbrain --skill cron-scheduler -a windsurf -y
SKILL.md
cron-scheduler.SKILL.mdname: cron-scheduler
version: 1.0.0
description: |
Schedule management with staggering, quiet hours, and wake-up override.
Validates schedules, prevents collisions, and gates delivery during quiet hours.
triggers:
- "schedule a job"
- "cron"
- "quiet hours"
- "what jobs are running"
tools:
- search
- get_page
- put_page
mutating: true
Cron Scheduler
> **Convention:** See `skills/conventions/test-before-bulk.md` — test every cron job on 3-5 items first.
Contract
This skill guarantees:
- Schedule staggering: max 1 job per 5-minute slot, no collisions
- Quiet hours gating: timezone-aware, with user-awake override
- Thin job prompts: jobs say "Read skills/X/SKILL.md and run it" (no inline 3000-word prompts)
- Idempotency: jobs can run twice without duplicate side effects
- Results saved as reports: `reports/{job-name}/{YYYY-MM-DD-HHMM}.md`
- One entry point: every job, workspace script and hook calls gbrain through
one wrapper that sets `GBRAIN_HOME` and keeps stderr and the exit code ([the wrapper](https://github.com/garrytan/gbrain/blob/master/docs/guides/cron-schedule.md#calling-gbrain-unattended))
Phases
1. **Define job.** Name, schedule (cron expression), skill to run, timeout. 2. **Validate schedule.** Check no collision with existing jobs (5-minute offset rule).
- Slots: :05, :10, :15, :20, :25, :30, :35, :40, :45, :50
- If collision detected, suggest the next available slot
3. **Check quiet hours.** Default: 11 PM - 8 AM local time.
- Override: user-awake flag (if user is active, quiet hours suspended)
- During quiet hours: save output to held queue
- Morning contact releases the backlog
4. **Register with host scheduler.** OpenClaw cron, Railway cron, crontab, or process manager. **Each registered entry should execute via Minions, not `agentTurn`.** See `skills/conventions/cron-via-minions.md` for the rewrite pattern (PGLite uses `--follow`, Postgres uses fire-and-forget + `--idempotency-key` on the cycle slot). GBrain's v0.11.0 migration auto-rewrites entries for built-in handlers; host-specific handlers need a code-level registration per `docs/guides/plugin-handlers.md`. 5. **Write thin prompt.** Job prompt is one line: "Read skills/{name}/SKILL.md and run it." 6. **Call gbrain through the wrapper.** Cron runs with another `HOME` and environment than your shell, so a bare `gbrain` (or `bun run src/cli.ts`) can find no database (every lookup silently empty) or act as a second host (`refresh_not_owner`). Register `gbrain-run <args>`, the wrapper in [cron-schedule.md](https://github.com/garrytan/gbrain/blob/master/docs/guides/cron-schedule.md#calling-gbrain-unattended): it sets `GBRAIN_HOME` (never `HOME`), loads the brain's env file and runs the installed binary. Log stderr to a file, check the exit code, keep hook output off stdout, and give each call a timeout of at least 10 s. The lines below write `gbrain-run`; doctor prints the bare command. `gbrain doctor --only cron_gbrain_home` warns about any crontab line or script that runs `src/cli.ts` directly or calls gbrain without the brain's `GBRAIN_HOME`.
Idempotency Requirement
Every cron job MUST be idempotent:
- Running the same job twice produces the same result (no duplicate pages, no duplicate timeline entries)
- Use checkpoint state files to track progress and resume interrupted runs
- Check for existing output before creating new output
Output Format
Job configuration saved. Report: "Job '{name}' scheduled at {cron expression}. Next run: {time}."
Multi-source brains: use `sync --all`, not per-source entries
When the brain has 2+ active sources (anything `gbrain sources list` shows with a non-null `local_path` that isn't archived), use one consolidated cron line instead of N per-source entries.
**Preferred (multi-source)**:
*/5 * * * * gbrain-run sync --all --parallel 4 --workers 4 --skip-failed >> /tmp/gbrain-cron.log 2>&1
This replaces N per-source lines AND auto-picks-up future sources without a crontab edit. Concurrency budget: `parallel × workers × 2 ≈ 32` connections during the wave (each per-file worker opens its own 2-connection pool). Stay under your Postgres `max_connections` setting.
**Avoid (legacy)**: separate `gbrain sync --source default` and `gbrain sync --source zion-brain` entries staggered by 5 minutes. They require manual deconfliction every time a new source is added, and a slow source can race a fast source on the legacy global `gbrain-sync` lock (v0.40.3.0+ uses per-source `gbrain-sync:<sourceId>` locks but the per-source cron pattern doesn't benefit from the parallelism that `--all --parallel` actually delivers).
`gbrain doctor` surfaces the recommended line as a `sync_consolidation` check whenever it detects 2+ active sources. Paste-ready from there.
Managed brain
A managed brain refuses the line above: managed sync needs `--no-pull` and rejects `--skip-failed` (`writer_coordinator_required`). Check the mode first: `gbrain sources writer status --json` reports `"mode": "managed"` or `"mode": "classic"`, and its `bindings` name each source's owner host.
On a managed brain, install this line instead, on the host that owns the sources:
*/15 * * * * gbrain-run sources git-reconcile >> /tmp/gbrain-cron.log 2>&1; gbrain-run sync --all --no-pull --hard-deadline 13m >> /tmp/gbrain-cron.log 2>&1
- `gbrain sources git-reconcile` brings every checkout on the host level with
its upstream; a managed checkout goes through `gbrain sources refresh` (a fetch and `git merge --ff-only`, then a managed sync of its sources), the only way it takes upstream commits. A level checkout costs one fetch, and autopilot already runs it each tick. The `;` is deliberate: the sync still runs when a reconcile refuses.
- `refresh_diverged`: the checkout has commits its upstream lacks, so
something commits outside gbrain (usually a script that writes files and runs `git commit` in
Read more
name: cron-scheduler version: 1.0.0 description: | Schedule management with staggering, quiet hours, and wake-up override. Validates schedules, prevents collisions, and gates delivery during quiet hours. triggers: - "schedule a job" - "cron" - "quiet hours" - "what jobs are running" tools: - search - get_page - put_page mutating: true
Cron Scheduler
> **Convention:** See `skills/conventions/test-before-bulk.md` — test every cron job on 3-5 items first.
Contract
This skill guarantees:
- Schedule staggering: max 1 job per 5-minute slot, no collisions
- Quiet hours gating: timezone-aware, with user-awake override
- Thin job prompts: jobs say "Read skills/X/SKILL.md and run it" (no inline 3000-word prompts)
- Idempotency: jobs can run twice without duplicate side effects
- Results saved as reports: `reports/{job-name}/{YYYY-MM-DD-HHMM}.md`
- One entry point: every job, workspace script and hook calls gbrain through
one wrapper that sets `GBRAIN_HOME` and keeps stderr and the exit code ([the wrapper](https://github.com/garrytan/gbrain/blob/master/docs/guides/cron-schedule.md#calling-gbrain-unattended))
Phases
1. **Define job.** Name, schedule (cron expression), skill to run, timeout. 2. **Validate schedule.** Check no collision with existing jobs (5-minute offset rule).
- Slots: :05, :10, :15, :20, :25, :30, :35, :40, :45, :50
- If collision detected, suggest the next available slot
3. **Check quiet hours.** Default: 11 PM - 8 AM local time.
- Override: user-awake flag (if user is active, quiet hours suspended)
- During quiet hours: save output to held queue
- Morning contact releases the backlog
4. **Register with host scheduler.** OpenClaw cron, Railway cron, crontab, or process manager. **Each registered entry should execute via Minions, not `agentTurn`.** See `skills/conventions/cron-via-minions.md` for the rewrite pattern (PGLite uses `--follow`, Postgres uses fire-and-forget + `--idempotency-key` on the cycle slot). GBrain's v0.11.0 migration auto-rewrites entries for built-in handlers; host-specific handlers need a code-level registration per `docs/guides/plugin-handlers.md`. 5. **Write thin prompt.** Job prompt is one line: "Read skills/{name}/SKILL.md and run it." 6. **Call gbrain through the wrapper.** Cron runs with another `HOME` and environment than your shell, so a bare `gbrain` (or `bun run src/cli.ts`) can find no database (every lookup silently empty) or act as a second host (`refresh_not_owner`). Register `gbrain-run <args>`, the wrapper in [cron-schedule.md](https://github.com/garrytan/gbrain/blob/master/docs/guides/cron-schedule.md#calling-gbrain-unattended): it sets `GBRAIN_HOME` (never `HOME`), loads the brain's env file and runs the installed binary. Log stderr to a file, check the exit code, keep hook output off stdout, and give each call a timeout of at least 10 s. The lines below write `gbrain-run`; doctor prints the bare command. `gbrain doctor --only cron_gbrain_home` warns about any crontab line or script that runs `src/cli.ts` directly or calls gbrain without the brain's `GBRAIN_HOME`.
Idempotency Requirement
Every cron job MUST be idempotent:
- Running the same job twice produces the same result (no duplicate pages, no duplicate timeline entries)
- Use checkpoint state files to track progress and resume interrupted runs
- Check for existing output before creating new output
Output Format
Job configuration saved. Report: "Job '{name}' scheduled at {cron expression}. Next run: {time}."
Multi-source brains: use `sync --all`, not per-source entries
When the brain has 2+ active sources (anything `gbrain sources list` shows with a non-null `local_path` that isn't archived), use one consolidated cron line instead of N per-source entries.
**Preferred (multi-source)**:
*/5 * * * * gbrain-run sync --all --parallel 4 --workers 4 --skip-failed >> /tmp/gbrain-cron.log 2>&1
This replaces N per-source lines AND auto-picks-up future sources without a crontab edit. Concurrency budget: `parallel × workers × 2 ≈ 32` connections during the wave (each per-file worker opens its own 2-connection pool). Stay under your Postgres `max_connections` setting.
**Avoid (legacy)**: separate `gbrain sync --source default` and `gbrain sync --source zion-brain` entries staggered by 5 minutes. They require manual deconfliction every time a new source is added, and a slow source can race a fast source on the legacy global `gbrain-sync` lock (v0.40.3.0+ uses per-source `gbrain-sync:<sourceId>` locks but the per-source cron pattern doesn't benefit from the parallelism that `--all --parallel` actually delivers).
`gbrain doctor` surfaces the recommended line as a `sync_consolidation` check whenever it detects 2+ active sources. Paste-ready from there.
Managed brain
A managed brain refuses the line above: managed sync needs `--no-pull` and rejects `--skip-failed` (`writer_coordinator_required`). Check the mode first: `gbrain sources writer status --json` reports `"mode": "managed"` or `"mode": "classic"`, and its `bindings` name each source's owner host.
On a managed brain, install this line instead, on the host that owns the sources:
*/15 * * * * gbrain-run sources git-reconcile >> /tmp/gbrain-cron.log 2>&1; gbrain-run sync --all --no-pull --hard-deadline 13m >> /tmp/gbrain-cron.log 2>&1
- `gbrain sources git-reconcile` brings every checkout on the host level with
its upstream; a managed checkout goes through `gbrain sources refresh` (a fetch and `git merge --ff-only`, then a managed sync of its sources), the only way it takes upstream commits. A level checkout costs one fetch, and autopilot already runs it each tick. The `;` is deliberate: the sync still runs when a reconcile refuses.
- `refresh_diverged`: the checkout has commits its upstream lacks, so
something commits outside gbrain (usually a script that writes files and runs `git commit` in
Other skills on gbrain.
More skills from other plugins.
agent-cost-report
Believable agent cost report for any period, default the last 7 full days PT, not counting today. Measured tokens from Claude…
bot-handoff
Keep a durable record of work passed between Bots in the shared Hindsight memory bank. Use when handing work to another Bot, when…
mempalace
Install, configure, and operate MemPalace, including a private local palace, a shared-brain hub, or a client joining an existing…
mempalace
Install, configure, and operate MemPalace, including a private local palace, a shared-brain hub, or a client joining an existing…
Questions about cron-scheduler.
- Which coding agents can use cron-scheduler?
- cron-scheduler installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

