Scheduled Cronjobs
Scheduled Cronjobs Server-side cron jobs on the dev server (user: ) that automate deployment monitoring, code quality, testing, security audits, and issue tr...
Scheduled Cronjobs
Server-side cron jobs on the dev server (user:
superdev) that automate deployment monitoring, code quality, testing, security audits, and issue triage. All AI maintenance chats are dispatched via OpenCode CLI (opencode run), configured inscripts/_opencode_utils.py.
Why This Exists
Continuous automated maintenance reduces manual toil: deploy failures are auto-investigated, dead code is removed nightly, tests run daily, and security is audited twice weekly.
How It Works
Overview
| Schedule | Script | Purpose |
|---|---|---|
0 10 * * 1-5 UTC |
daily-meeting.sh |
Daily standup: OpenCode chat + email link |
*/2 * * * * |
check-deploy-status.sh |
Watch Vercel for build failures |
02:00 Mon-Fri |
nightly-dead-code-removal.sh |
Remove detected dead code |
02:00 Mon+Thu |
weekly-codebase-audit.sh |
Top 5 improvement findings (plan only) |
02:15 Mon-Fri |
nightly-quick-wins.sh |
Quick-win improvements (Haiku, plan only) |
02:30 Tue+Fri |
security-audit.sh |
Security code review (plan only) |
02:30 Wed+Sat |
red-teaming.sh |
External attacker simulation (GET only) |
02:35 Mon-Fri |
nightly-pattern-consistency.sh |
Pattern consistency scan (Haiku, plan only) |
02:50 Mon-Fri |
nightly-code-structure.sh |
Code structure cleanup suggestions |
03:00 Mon-Fri |
tests.py run --daily |
Full test suite (Playwright + pytest) |
04:10 Tue+Fri |
nightly-ui-design-review.sh |
UI design system/code review (plan only) |
04:30 Mon+Thu |
nightly-apple-parity-review.sh |
Apple/web parity review (plan only) |
04:50 Sun |
nightly-seo-audit.sh |
Deep SEO optimization review (plan only) |
03:20 Sun |
weekly-technical-debt.sh |
Deterministic debt scan + OpenCode top 5 recommendations |
05:15 Mon |
weekly-contract-audits.sh |
Deterministic contract audits + OpenCode recommendations |
* * * * * |
update_obsidian_daily_note.py |
Refresh Obsidian daily note stats/activity |
0 8-18 * * * (GHA) |
.github/workflows/prod-smoke.yml |
Hourly prod smoke (reachability + signup+gift card + login+chat), 10–20 Berlin (OPE-76) |
04:30 daily (Dependabot) |
.github/dependabot.yml |
Daily npm/pnpm version update PRs with cooldown |
*/1h (xx:30) |
check-dependabot-daily.sh |
Process Dependabot security alerts |
*/1h (xx:35) |
check-eu-vulns-daily.sh |
EU/OSV/NVD vulnerability detection |
02:00 Sun |
docker-cleanup.sh |
Remove dangling images, build cache; aggressive mode at >90% disk |
01:30 daily |
cleanup-opencode-sessions.sh |
Delete OpenCode chats older than 14 days, except TODO sessions |
Consolidated (2026-03-27):
nightly-issues-check.shandnightly-workflow-review.shhave been folded into the daily meeting. Their helpers (_issues_checker.py,_workflow_review_helper.py) are kept as importable libraries.
Job Details
Daily standup meeting (10:00 UTC weekdays): daily-meeting.sh creates a persisted OpenCode chat titled daily-meeting YYYY-MM-DD, asks the daily-meeting skill to gather data inline, and emails a deep link to the configured recipient. The OpenCode web URL is built as ${OPENCODE_WEB_BASE_URL}/${base64url(project_path)}/session/${session_id}. No Claude launcher and no Zellij session are involved. The meeting remains interactive: it presents one agenda section at a time and saves scripts/.daily-meeting-state.json plus scripts/.tmp/daily-meeting-summary-<date>.md only after the user confirms priorities. Consolidates former nightly-workflow-review.sh and nightly-issues-check.sh. Manual: ./scripts/daily-meeting.sh or /daily-meeting skill. Env: DAILY_MEETING_NOTIFY_EMAIL (or SERVER_OWNER_EMAIL/ADMIN_NOTIFY_EMAIL fallback), OPENCODE_WEB_BASE_URL, INTERNAL_API_SHARED_TOKEN, INTERNAL_API_URL.
Deploy status checker (*/2 min): Checks git log for recent commits; if found, queries Vercel API for build status. On ERROR/CANCELED, dispatches an OpenCode repair chat with the build log. State: scripts/.deploy-checker-state.json. Env: VERCEL_TOKEN.
Dead code removal (02:00): Runs find_dead_code.py (up to 50 items across Python/TypeScript/Svelte/CSS). Dispatches an OpenCode chat to remove and commit. Skips if HEAD unchanged. State: scripts/.dead-code-removal-state.json.
Codebase audit (Mon+Thu 02:00): Uses 2 weeks of git history to find top 5 improvements (security, performance, reliability, quality). Plan mode only – no implementation. State: scripts/.audit-state.json.
Daily test run (03:00): Full Playwright E2E + pytest suite. Sends summary email on completion + Discord fallback post (OPE-76), writes last-passed-tests.json / last-failed-tests.json, pushes one OpenObserve summary, and archives to test-results/daily-run-YYYY-MM-DD.json. The scheduled runner is notification-only: it does not start OpenCode auto-fix, so failed-test remediation can never hold the daily lock and block the next scheduled run. Manual follow-up can still use scripts/auto_fix_failed_tests.py --from-daily-run when an operator intentionally wants controller-owned fixes. Env: E2E_DAILY_RUN_ENABLED=true, ADMIN_NOTIFY_EMAIL, INTERNAL_API_SHARED_TOKEN, OPENCODE_WEB_BASE_URL, DISCORD_WEBHOOK_DEV_NIGHTLY (optional), DISCORD_WEBHOOK_TEST_FIXES (optional dedicated manual auto-fix channel).
Obsidian daily note updater (every minute): Refreshes today’s local daily note under vaults/memory/Daily Notes/ with changed note links, same-day git commits, and cached server stats. Preserves manual content outside <!-- AUTO:* --> sections. Log: logs/obsidian-daily-note.log. State: vaults/memory/.obsidian-auto/daily-note-state/.
Prod smoke (GitHub Actions, hourly 10–20 Europe/Berlin): Runs three Playwright specs against the live production server: (1) reachability pre-flight, (2) fresh signup + reusable domain-bound gift card redemption + first chat (no Stripe), (3) login + chat on a persistent prod test account. On any failure, the shared composite action .github/actions/notify-test-failure posts to a Discord webhook and sends an email via Brevo — both sends independent so a single channel outage never masks the failure. No dependency on dev server uptime. Secrets: PROD_BASE_URL, PROD_SMOKE_GIFT_CARD_CODE, PROD_SMOKE_EMAIL_DOMAIN, PROD_SMOKE_MAILOSAUR_API_KEY, PROD_SMOKE_MAILOSAUR_SERVER_ID, OPENMATES_PROD_TEST_ACCOUNT_{EMAIL,PASSWORD,OTP_KEY}, DISCORD_WEBHOOK_PROD_SMOKE, PROD_SMOKE_EMAIL_TO, BREVO_API_KEY. The gift card’s allowed_email_domain must exactly match the Mailosaur server subdomain — suffix matches would let any Mailosaur customer redeem the card.
Dependabot version updates (GitHub native, daily 04:30 UTC): Opens npm/pnpm version-update PRs against dev. Routine patch/minor updates use a 48-hour cooldown (cooldown.default-days: 2) to avoid newly published malicious npm versions during supply-chain incidents; major updates use a 14-day cooldown for extra stability. This is separate from security-alert processing below, which remains immediate for critical/high/medium advisories. pnpm also enforces minimumReleaseAge: 2880 minutes in pnpm-workspace.yaml so manual and CI dependency resolution follow the same 48-hour delay.
Issues check: Consolidated into daily meeting (2026-03-27). Helper _issues_checker.py still available as importable library.
Admin issue investigation: automatic OpenCode handoff from admin issue reports is disabled. Admin reports still return an issue ID; copy that ID into OpenCode manually when investigation is needed.
Dependabot check (hourly at xx:30): Fetches critical/high/medium alerts via gh CLI. Dispatches fix session for new or stale (>7 days) alerts. No-ops in seconds when no new alerts are found (no Claude session spawned). Uses sessions.py deploy for commits. Resolved entries auto-pruned after 72h. State: scripts/dependabot-processed.json.
EU vulnerability check (hourly at xx:35, 5 min after Dependabot): Queries OSV + NVD for vulnerabilities Dependabot misses. Cross-refs against dependabot-processed.json. No-ops in seconds when no new vulns found. Uses sessions.py deploy for commits. Resolved entries auto-pruned after 72h. State: scripts/eu-vuln-processed.json.
Workflow review: Consolidated into daily meeting (2026-03-27). Helper _workflow_review_helper.py still available as importable library.
Security audit (Tue+Fri 02:30): Reviews files changed since last audit. Top 5 critical security issues with OWASP mapping. Monthly full sweep. Acknowledged findings suppressed via _security_helper.py acknowledge. State: .claude/security-audit-state.json (gitignored).
Red team probe (Wed+Sat 02:30): Simulates external attacker against dev endpoints (GET/HEAD/OPTIONS only, max 5 req/endpoint, 20-min timeout). Three phases: reconnaissance, external probing, safe exploitation. No destructive requests. Uses --permission-mode plan with --allowedTools "Read,Grep,Glob,Bash(curl *)".
Code structure cleanup (02:50 daily): Scans for repository hygiene issues — gitignore gaps, open-source readiness (leaked internal values), folder organization, file consolidation, naming inconsistencies, stale artifacts. Haiku, plan mode, 25-min soft limit / 30-min hard kill. Suggestions only, no code changes. Uses _nightly_scanner_helper.py with rotating sector schedule. Output: logs/nightly-reports/code-structure.json. Manual: ./scripts/nightly-code-structure.sh [--dry-run].
UI design review (Tue+Fri 04:10): Starts a read-only OpenCode chat that inspects the current web and Apple UI codebase, using recent UI commits only as prioritization context. Reports top recommendations for design-system consistency, web/Apple UI unification, redundant component/style patterns, readability, settings UI standards, and hook/lint opportunities justified by repeated current-code or recent-commit patterns. Output: logs/nightly-reports/ui-design-review.json. Manual: ./scripts/nightly-ui-design-review.sh [--dry-run].
Apple parity review (Mon+Thu 04:30): Generates test-results/apple-parity-inventory.json, then starts a Linux-safe read-only OpenCode chat that inspects current Swift and web source, apple/SVELTE_SWIFT_COUNTERPARTS.md, and recent web UI commits to recommend the highest-priority Apple parity follow-ups. Output: logs/nightly-reports/apple-parity-review.json. Manual: ./scripts/nightly-apple-parity-review.sh [--dry-run].
SEO audit (Sun 04:50): Starts a read-only OpenCode chat that combines safe production GET/HEAD checks against openmates.org with current SvelteKit source inspection. This is deeper than the daily meeting SEO smoke check and reports prioritized improvements for sitemap coverage, SSR/prerender, metadata, OG/Twitter tags, JSON-LD, hreflang, and internal linking. Output: logs/nightly-reports/seo-audit.json. Manual: ./scripts/nightly-seo-audit.sh [--dry-run].
Technical debt scan + recommendations (Sun 03:20): Runs technical_debt_scan.py without AI to rank source hotspots by size, complexity-style signals, suppressions, broad exception/catch use, debug logging, store-internal imports, backend cross-skill imports, duplication fingerprints, test-name proximity, and six-month churn. The scanner compares against scripts/.technical-debt-state.json so the follow-up can consider previous-run deltas. After reports are written, _technical_debt_helper.py starts a read-only OpenCode chat to recommend the top five next improvement steps. Outputs: logs/nightly-reports/technical-debt.json, logs/nightly-reports/technical-debt.md, and logs/nightly-reports/technical-debt-analysis.json summary metadata. Manual: ./scripts/weekly-technical-debt.sh [--dry-run|--scan-only].
Deterministic contract audits + recommendations (Mon 05:15): Runs static repo-specific checks without AI or network calls: backend app/skill architecture boundaries, encryption key access patterns, settings UI contract rules, app skill/provider metadata, and export/import invariants. Writes test-results/contract-audits/latest.json, a dated weekly JSON artifact, and logs/nightly-reports/contract-audits.json for daily-meeting and on-demand agent processing. Sends a compact email summary via Brevo (BREVO_API_KEY) or the internal test-summary email endpoint (INTERNAL_API_SHARED_TOKEN). After the JSON is written, starts a read-only OpenCode chat via _contract_audit_review_helper.py to analyze the report and recommend the top next steps; that chat is referenced from logs/nightly-reports/contract-audit-review.json. Manual: ./scripts/weekly-contract-audits.sh [--dry-run], ./scripts/weekly-contract-audits.sh --skip-review, or python3 scripts/run_contract_audits.py --dry-run.
Docker cleanup (Sun 02:00): docker system prune for dangling images, stopped containers, unused volumes.
OpenCode session cleanup (01:30 daily): Deletes OpenCode chats older than 14 days when their title does not contain TODO, using opencode session delete so session storage is removed with the SQLite row. Logs to logs/opencode-cleanup.log and writes logs/nightly-reports/session-cleanup.json for daily meeting consumption. Manual: ./scripts/cleanup-opencode-sessions.sh.
Agent trigger watcher (@reboot): Polls scripts/.agent-triggers/ every 5s for JSON trigger files from admin sidecar. Dispatches OpenCode investigation chats; completed triggers moved to done/.
Agent CLI Dispatch
Most background maintenance helpers use scripts/_opencode_utils.py:run_opencode_session() which invokes:
opencode run \
--title "<session-title>" \
--format json \
[--dangerously-skip-permissions] \
"Read scripts/.tmp/<prompt>.md in full and follow all instructions precisely."
Session IDs are extracted from OpenCode JSONL output and logged for traceability. Read-only jobs include explicit no-edit/no-commit instructions in the prompt message; write jobs use --dangerously-skip-permissions.
The daily standup is the exception: scripts/_opencode_daily_meeting.py invokes opencode run --format json --title "daily-meeting <date>" so the chat appears directly in OpenCode web. Cron should configure the public web base URL and recipient via environment, not source code.
Manual Invocation
Most maintenance scripts support --dry-run (show prompt, skip agent) or --force (bypass guards):
./scripts/check-deploy-status.sh --dry-run
./scripts/nightly-dead-code-removal.sh --force --category python
./scripts/run-tests-daily.sh --force
REVIEW_DATE=2026-03-17 bash scripts/nightly-workflow-review.sh
Adding a New Job
- Shell entrypoint in
scripts/(source.env, header comment with schedule). - Python helper in
scripts/_<name>_helper.pyif needed. - Prompt template in
scripts/prompts/if calling an agent with a large reusable prompt. - Crontab entry via
crontab -e. - Update this doc.
Related Docs
- Health Checks – Celery Beat tasks (not cron) for service monitoring
- Daily Test Run – test infrastructure details