| name | scheduled-job-best-practices |
| description | Patterns for resilient, non-interactive scheduled opencode jobs |
Use This Skill
Put this line at the very top of any scheduled job prompt:
@scheduled-job-best-practices
Then write your task below it.
Core Principles
- No magic injection. Do not assume placeholders like TODAY exist. Compute runtime values using tools (bash) during the run.
- Non-interactive. Scheduled jobs must not rely on QR codes, manual logins, or confirmation dialogs.
- Idempotent. Make reruns safe (maintain a seen/state file; avoid duplicate messages).
- Observable. Print a short summary at the end with status + outputs.
- Minimal side effects. Write durable artifacts under outputs/ in the job workdir.
Runtime Values: Dates
If you need local dates, compute them at runtime.
macOS
TODAY="$(date +%F)"
TOMORROW="$(date -v+1d +%F)"
Linux
TODAY="$(date +%F)"
TOMORROW="$(date -d 'tomorrow' +%F)"
Portable snippet
if [ "$(uname)" = "Darwin" ]; then
TODAY="$(date +%F)"
TOMORROW="$(date -v+1d +%F)"
else
TODAY="$(date +%F)"
TOMORROW="$(date -d 'tomorrow' +%F)"
fi
If timezone matters, set TZ explicitly (example: TZ=America/Los_Angeles date +%F).
Preflight Checklist
Before doing any expensive work:
- Confirm required tools are available (browser, network, etc).
- Confirm required env vars exist (source .env only if needed).
- If a dependency is missing/offline, stop early and emit a single concise reason.
Notifications (Telegram)
Prefer the Telegram Bot API (non-interactive) over web.telegram.org.
Output Contract
End every run with a compact summary:
- Status: success | skipped | failed
- Reason (1 line)
- Outputs written (paths)
- Notifications sent (message_id, chat_id) if applicable
Idempotency Pattern
When notifying about “new” items (deals, alerts, etc.):
- Store a seen list in outputs//seen.json
- Only notify on items not in seen.json
- Update seen.json after sending