Recurring OpenCode agent jobs on your OS scheduler — built for OpenCode v2, with Telegram delivery built in.
Built on the ideas of different-ai/opencode-scheduler (MIT), rebuilt for OpenCode v2: zero-dependency TypeScript, a real CLI, and first-class delivery to Telegram (or any webhook) instead of logs-only.
Scheduled agent jobs are only useful when two things hold: the scheduler must be
reliable (systemd timers, Persistent=true catch-up after sleep, no overlap,
hard timeouts) and the result must reach you (Telegram DM > log file you'll
never read).
git clone https://github.com/jaygupta17/opencode2-scheduler && cd opencode2-scheduler
npm install
npm run build
node dist/cli.js doctor # environment checks
node dist/cli.js install-skill # teach your agent how to manage jobsOr link the CLI:
npm link # provides `opencode2-scheduler` on PATHopencode2-scheduler add \
--name morning-brief \
--cron "30 7 * * *" \
--description "HN + AI news + PRs" \
--prompt "Summarize today's Hacker News AI stories, new model releases, and any GitHub PRs needing my review. Max 15 lines, plain text for Telegram."
opencode2-scheduler list # jobs + next runs
opencode2-scheduler run morning-brief # fire now
opencode2-scheduler logs morning-brief --tail 40
opencode2-scheduler rm morning-brief| Command | Purpose |
|---|---|
add |
create a job (writes job JSON + systemd service/timer, enables it) |
list |
all jobs, schedule, enabled, last status, next run |
show <name> |
full job JSON + unit status + last run record |
run <name> |
fire now, asynchronously |
logs <name> [--tail N] |
supervisor output |
enable / disable <name> |
toggle the timer without deleting |
rm <name> |
remove units + files |
test-notify |
send a Telegram test message |
install-skill [--project] |
install the agent skill (global or project .opencode/skill/) |
doctor |
environment + config checks |
--workdir --model --agent --server --session --title --timeout
--notify telegram|none|webhook:<url> --disabled --description
Telegram is first-class. Resolution order for token/chat:
- the job's
notify.token/notify.chatId ~/.config/opencode/scheduler/config.json
{
"telegram": { "token": "123:ABC", "chatId": "8243660338" },
"defaultModel": "commandcode/xiaomi/mimo-v2.6-flash",
"defaultServer": "http://100.80.54.32:49374",
"env": { "TZ": "Asia/Kolkata" }
}A run sends exactly one message: ⏰ <job> · <status> plus the agent's final
text (truncated to Telegram limits). Failures send ❌, timeouts ⏱️.
| Platform | Backend | Catch-up after sleep | Next-run in list |
|---|---|---|---|
| Linux (systemd) | systemd --user units |
✅ Persistent=true |
✅ exact |
| macOS | launchd LaunchAgent |
✅ runs on wake | estimated |
| Linux (no systemd) / other POSIX | cron managed block |
❌ (cron limitation) | estimated |
| Windows | not supported yet | — | — |
doctor shows which backend is active. Jobs are portable: the same
jobs/<name>.json works on a Mac after opencode2-scheduler add-ing it there
(credentials to deliver — Telegram token/chat — live in config.json).
- OS-native scheduling — systemd timers on Linux, LaunchAgents on macOS, managed crontab blocks as fallback; no daemon of our own to keep alive
- catch-up — missed ticks (laptop asleep/off) run on wake where the OS
supports it (systemd
Persistent=true, launchd on-wake) - pid lock — overlapping ticks are skipped, never queued
- hard timeout — SIGTERM, then SIGKILL of the whole process group
- append-only run records —
runs/<name>.jsonl, last status mirrored into the job file - env hygiene — inherited
OPENCODE_*variables are stripped so scheduled runs can't accidentally attach to the wrong server; configenvinjects what a job needs
~/.config/opencode/scheduler/
├── config.json
├── jobs/<name>.json # the job definition (edit it, it's yours)
├── runs/<name>.jsonl # run records
├── logs/<name>.log # supervisor + opencode output
└── locks/<name>.json # live-run lock
npm run build # tsc -> dist/
npm test # builds, then node --test (29 tests: cron, store, units, supervisor E2E)
npm run typecheckMIT. Portions derived from opencode-scheduler (Copyright © Different AI) — see LICENSE.