OpenMates Docs Open Chat

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...

[T:documentation.sender_name]

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 in scripts/_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.sh and nightly-workflow-review.sh have 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

  1. Shell entrypoint in scripts/ (source .env, header comment with schedule).
  2. Python helper in scripts/_<name>_helper.py if needed.
  3. Prompt template in scripts/prompts/ if calling an agent with a large reusable prompt.
  4. Crontab entry via crontab -e.
  5. Update this doc.