feat(web): schedules — auto-create pi sessions on a cadence#79
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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).
/schedulespage reached from a calendar button beside the Timeline/Projects toggle on the index.What's in the diff
Backend (Go)
internal/schedules/—Schedule/Runtypes, SQLite store,NextFireviagithub.com/robfig/cron/v3(new dep), pure & table-driven tested.internal/server/scheduler.go— 30-s tick loop and thefireSchedulerunner 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— addsNotifyScheduleDone;status.goroutes the running→idle transition to a schedule-specific push when the finished session is schedule-created.internal/ui/embedded/assets/sw.js— always showsschedule-donenotifications (no foreground-suppress, distinct tag).Frontend (Svelte 5)
web/src/routes/SchedulesPage.svelte,/schedulesroute inApp.svelte, "Schedules" nav button inIndexHeader.svelte.web/src/index/schedules.js— API helpers + cron preset compile/parse (buildCron,parseCron,describeFrequency).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).schedules.*i18n keys added to all 14 locale files.Docs & tests
docs/sequence-flows/schedules.md+ index/backend doc updates.e2e/tests/schedules.spec.ts) covers create → Run-now → run log → delete, includes amax-width: 880pxstyling-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 locallycd e2e && npx playwright test tests/schedules.spec.tsacross Desktop Chrome / Safari / Mobile Chrome — 9/9 passed locally/scheduleson 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