Skip to content

feat(web): schedules — auto-create pi sessions on a cadence#79

Merged
setkyar merged 8 commits into
mainfrom
feat/schedules-page
Jun 16, 2026
Merged

feat(web): schedules — auto-create pi sessions on a cadence#79
setkyar merged 8 commits into
mainfrom
feat/schedules-page

Conversation

@setkyar

@setkyar setkyar commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a Schedules feature: define automations that run pi on a cron/preset cadence (or via Run-now). Each firing creates a fresh pi session, sends the schedule's instructions as the first message, and records the run so created sessions can be filtered and surfaced in a run log. Scheduled runs fire a schedule-specific web push on completion (shown even when the app is foregrounded).

  • New /schedules page reached from a calendar button beside the Timeline/Projects toggle on the index.
  • Editor with name, instructions, model search, thinking level, project dir (optional → home), and frequency: manual, hourly, daily, weekdays, weekly, or custom cron — all stored as a standard cron expression with a per-schedule IANA timezone.
  • Mobile uses a floating + (matching the sessions index); the header "New schedule" button is hidden on small viewports.
  • Missed runs while the server was down are skipped on startup.
  • Schedules and runs persist in SQLite; run rows double as the session → schedule mapping that tags created sessions and routes the schedule-specific push.

What's in the diff

Backend (Go)

  • internal/schedules/Schedule/Run types, SQLite store, NextFire via github.com/robfig/cron/v3 (new dep), pure & table-driven tested.
  • internal/server/scheduler.go — 30-s tick loop and the fireSchedule runner that creates the session, ensures the worker, and sends instructions.
  • internal/server/schedules_api.go/api/schedules (list/create), /api/schedule (read/update/delete by ?id), /api/schedule/run (Run-now), /api/schedule/runs (log).
  • internal/server/push.go — adds NotifyScheduleDone; status.go routes the running→idle transition to a schedule-specific push when the finished session is schedule-created.
  • internal/ui/embedded/assets/sw.js — always shows schedule-done notifications (no foreground-suppress, distinct tag).

Frontend (Svelte 5)

  • web/src/routes/SchedulesPage.svelte, /schedules route in App.svelte, "Schedules" nav button in IndexHeader.svelte.
  • web/src/index/schedules.js — API helpers + cron preset compile/parse (buildCron, parseCron, describeFrequency).
  • Polished UI with Lucide icons (Play/Pause/Edit/Runs/Delete), Active/Paused pills, Next/Last meta chips, run log, and a clean editor modal with focus rings.
  • All styles live in internal/ui/embedded/styles/schedules.css (the live SPA shell inlines global stylesheets and doesn't link Vite's component CSS — so scoped <style> blocks would render unstyled; this approach matches every other route in the app).
  • New schedules.* i18n keys added to all 14 locale files.

Docs & tests

  • New docs/sequence-flows/schedules.md + index/backend doc updates.
  • Go unit tests (cron, store, run lifecycle, fireSchedule, handlers); Vitest tests for the cron helpers.
  • Playwright E2E (e2e/tests/schedules.spec.ts) covers create → Run-now → run log → delete, includes a max-width: 880px styling-applied guard, and is layout-aware (header button on desktop, FAB on mobile). Verified passing on Desktop Chrome, Desktop Safari, and Mobile Chrome.

Test plan

  • make check (lint, format, knip, vitest, Go tests, build, vet, install tests) — green locally
  • cd e2e && npx playwright test tests/schedules.spec.ts across Desktop Chrome / Safari / Mobile Chrome — 9/9 passed locally
  • Manually visit /schedules on desktop and mobile — header button vs floating + behavior, editor open/save, Run-now navigates to created session, run log shows entry, delete removes the card
  • Subscribe to push notifications and run a scheduled session to completion — verify the schedule-specific push fires (not the generic "Response ready")

setkyar added 8 commits June 15, 2026 01:24
Schedules run pi automatically on a cron/preset cadence (or on demand via
Run-now). Each firing creates a fresh pi session, sends the schedule's
instructions as the first message, and records the run so created sessions can
be filtered and surfaced in a run log. Scheduling state lives in SQLite; the
cron math is in the new internal/schedules package while the firing loop and
runner live in internal/server alongside the chat workers.

On the running -> idle transition, scheduled runs send a schedule-specific web
push (shown even when the app is foregrounded) instead of the generic done
notification. Missed runs while the server is down are skipped.

Adds the /schedules SPA page (model search, frequency presets + custom cron,
configurable time/day/timezone, run log) reachable beside the Timeline/Projects
toggle. New schedules.* i18n keys are translated into all locales.
Adds e2e/tests/schedules.spec.ts driving the /schedules UI against the stub pi
worker: opening the page from the index nav, creating a manual schedule,
Run-now firing into a created session, the run log linking back to that session,
deletion, and a preset schedule reporting a computed next-run time. Adds stable
data-testid hooks to SchedulesPage so the spec doesn't depend on i18n text.

Verified passing on Chromium, Firefox, WebKit, and Mobile Chrome.
The live SPA shell inlines a fixed set of embedded global stylesheets
(appStylesheets in spa_page.go) and never links Vite's component CSS bundle, so
SchedulesPage's scoped <style> block was built but never loaded — the page
rendered completely unstyled. Move the styles into a new embedded
internal/ui/embedded/styles/schedules.css (namespaced under .schedules-page /
.schedule-editor to avoid colliding with global classes like the chat picker's
.model-item) and inline it in the shell. Drop the dead component <style>.

Adds an e2e assertion that .schedules-page resolves max-width:880px so an
unstyled regression fails the suite instead of passing silently.
The "Schedules" nav button had the same scoped-style bug as the page: its
styles lived in IndexHeader's <style> block, which the live SPA shell never
loads, so it rendered as a default white box next to the styled Timeline/
Projects toggle. Move those styles into index.css to match the segmented
control, with a calendar icon.

Redesign the schedules page to match the app's design language (color-mix
surfaces, dim borders, --accent, compact type): proper cards with an
Active/Paused status pill, a cadence line, Next/Last tag chips, Lucide icons on
every action (Run now/Pause/Edit/Runs/Delete), a styled run log, an empty
state, and a cleaner editor modal with focus rings and a close button. Adds the
needed Lucide icons (Play, Pause, Trash2, Clock, CalendarClock) to icons.js and
a schedules.active key across all locales.
On mobile the header "New schedule" button is hidden in favor of a floating +
(reusing the sessions index .new-session-btn), matching the homepage. Raise the
editor modal above the floating button's z-index so it can't intercept clicks on
the editor on small screens. Make the e2e spec layout-aware (click header on
desktop, the + on mobile); verified on Desktop Chrome/Safari and Mobile Chrome.
# Conflicts:
#	internal/server/server.go
#	web/src/App.svelte
#	web/src/shared/locales/de.js
#	web/src/shared/locales/es.js
#	web/src/shared/locales/fil.js
#	web/src/shared/locales/fr.js
#	web/src/shared/locales/id.js
#	web/src/shared/locales/ja.js
#	web/src/shared/locales/km.js
#	web/src/shared/locales/lo.js
#	web/src/shared/locales/ms.js
#	web/src/shared/locales/my.js
#	web/src/shared/locales/th.js
#	web/src/shared/locales/vi.js
#	web/src/shared/locales/zh.js
Host the editor in a FullScreenSheet (bottom-sheet on mobile, centered
dialog on desktop) and replace the unusable native datalist project
picker with a themed, scrollable suggestions popup.
@setkyar setkyar merged commit d87fe42 into main Jun 16, 2026
5 checks passed
@setkyar setkyar deleted the feat/schedules-page branch June 16, 2026 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant