feat(automations): scheduled triggers, default-on, redesigned surface, creation from a prompt - #985
Conversation
…rface, creation from a prompt Spec-first for the Claude Design export "cezar Automations": adds a schedule trigger kind, flips automations default-on, rebuilds the surface to the design from named primitives, and absorbs the pending automations-from-prompt patch as the last phase. Design screenshots, the kit's screen source, primitives, tokens and the patch live under the spec's assets. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rd flush Phase 1 of spec 2026-09-14-automations-redesign. The composer's chip class and the Tasks group-by control now come from one component each; nothing else changes shape. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…run route Phases 2–3 of spec 2026-09-14-automations-redesign. - A second trigger kind, `schedule` (daily / weekdays / weekly / every N hours, in the server's zone), evaluated by the existing workspace timer through a new ScheduleRunner: one receipt per occurrence, an age rule that fires at most one missed occurrence after any gap and skips the rest, auto-pause after three launch failures, held leases and duplicates never counted. The occurrence math lives in the contract (Node-free, Intl only) so the cockpit previews exactly what the timer fires; the usage-limit resume clock now shares it. - Every registered project gets a scheduler handle; the GitHub sub-object is present only for a github.com remote, so a repo without one still fires its schedules. - capabilities.automations is default-on; CEZ_AUTOMATIONS=0 opts out. A poll left enabled and idle longer than its lookback is re-baselined at boot so the flip cannot launch a backlog. README, .env.example, AGENTS.md and BACKWARD_COMPATIBILITY.md carry the break. - Scheduled launches write the new optional RunRecord.automationTrigger; `automation` is untouched so a downgrade keeps every run. task.dispatch maps to the dispatch intent and a review-child prompt suffix, ignored when dispatch is off. - GET /automations answers timeZone, this-week stats and per-row nextRunAt / lastRun / runs7d / costUsd7d; GET /automation-log answers the runs it names with their dispatch children; POST /automations/:id/run fires a schedule by hand; retry is kind-aware; GET /workspace/automation-templates lists other projects' definitions. - AutomationStore.setState is read-modify-write so two cockpits converge. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…I helpers; nav no longer forge-gated Phase 4 foundation of spec 2026-09-14-automations-redesign: the route owns the gate and the ?view= param, one query feeds every screen and invalidates on automation-change, row actions live in one hook, and the client gains run / delete / templates. The Automations nav item now follows capabilities.automations alone — a schedule needs no GitHub remote. The old page is replaced by placeholders the screen phases fill in. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…omation CLI, built-in skill, system-prompt part A user can now type "whenever a PR is opened, review it" into New task and get an automation instead of a one-off run. Two ways in, one mechanism underneath: - `cez automation schema|create|update|check|list|show|enable|pause|delete` — a thin client over the existing automations routes, addressed by the same CEZ_API_URL / CEZ_PROJECT_ID / CEZ_BIN the dispatch CLI uses. Definitions travel as JSON (--file, --json or stdin); create is paused unless --enable; check queues a preview and polls it; update merges over the editable keys and echoes the revision. - A short automations part composed into every task's system prompt at both session construction sites, so an agent recognises the intent and knows the CLI. - The built-in `create-cezar-automation` skill (source `builtin`, interactive), appended last to the catalog so a repo skill of the same name shadows it, plus a "Create an automation" composer template assigned to it. All of it gated on capabilities.automations AND the cockpit transport (automationsReachable): a headless run or a cockpit with CEZ_AUTOMATIONS unset composes nothing, lists nothing, offers nothing — the dispatch lesson (spec 2026-09-10 A2/A8). Spec: .ai/specs/2026-09-13-automations-from-prompt.md Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Htes33kPGJXohZYwtv7LYG
… cez automation add / run Phase 7 of spec 2026-09-14-automations-redesign, on top of the applied from-prompt patch: the schema reference shows both kinds, the always-on prompt part recognises "every day at" / "on weekdays" / "every N hours" as an automation, the skill playbook previews a poll and reports a schedule's next occurrence, `cez automation add` builds the same create body from flags (--cron for the four schedule shapes, --on/--every for a poll; anything flags cannot carry exits 2 pointing at the JSON form), `cez automation run` fires a schedule by hand, and the gating tests follow the default-on flag. The composer's Create-an-automation template names schedule triggers too. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Phase 6 of spec 2026-09-14-automations-redesign: rows with the result dot, reason, cost and task link; dispatch children nested under a run; kind-aware retry; result/event filters; refreshed on automation-change. The routes test follows the new opted-out wording. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…, week and day calendars Phase 4 of spec 2026-09-14-automations-redesign, pixel-matched to the design kit: the table with state / trigger / runs-as / next / last / 7-day columns, the this-week strip, the row menu with a delete confirm, the 360px next-runs rail over the shared occurrence math, and the week and day calendars with the poll band, today tint and now line — all rendered in the server's zone. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…fields, run-as, dispatch, preview, Copy as CLI Phase 5 of spec 2026-09-14-automations-redesign, pixel-matched to the design kit: a draft model round-tripping both kinds, the palette (built-in and other projects' automations), the four schedule shapes with the derived cron, multi-select events with the bounded filters, the composer's own pills for workflow / runner / model / base, the dispatch row, the next-five-runs preview off the shared occurrence math, the Copy as CLI card and the last-run card; 409 on a stale revision surfaces a reload, 400s land under their section. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nd, log, week, rail; GitHub poll preview and baseline; phone sweep Phase 8 of spec 2026-09-14-automations-redesign. The first live run caught a real defect: the built-in templates named a workflow this repo does not ship, so a launch failed with "unknown workflow" — the templates now name none (the cockpit default applies) and the palette keeps a template's workflow only when the cockpit lists it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…sockets and settles the rail before its capture The phone sweep showed the editor's Save button pushed out of the 56px header at 390px; the header now wraps below md and the template toggle drops its label there. The e2e helper closes each socket and retries once, which is what turned a spurious ECONNRESET on an idled keep-alive socket into a green run. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
🤖 |
# Conflicts: # packages/web/src/components/picker-pill.tsx
🔍 Code Review: feat(automations): scheduled triggers, default-on, redesigned surface, creation from a promptVerdict❌ request changes — one security blocker (unescaped shell interpolation in "Copy as CLI") and one documentation blocker (no CHANGELOG entry for the acknowledged breaking default-on flip), plus several majors around concurrency-evidence, a bundle-size regression, and a silent round-trip data loss. Core scheduling logic (DST handling, catch-up/skip semantics, the boot re-baseline that prevents a backlog burst on upgrade) is sound and well tested. 🎯 SummaryAdds a second automation trigger kind (cron-like schedules, DST-safe) beside the existing GitHub poll, flips automations to on-by-default ( Findings⛔ Blocker
|
| Command | Status | Evidence or limitation |
|---|---|---|
npm run typecheck |
✅ PASS | clean across contract/client/server/web |
npm test |
✅ PASS (verified) | 6901/6907 passed in-sandbox; the 6 failures (git-worktree.test.ts, automations-api.test.ts, git-changes.test.ts, git.test.ts, health-forge.test.ts, projects-api.test.ts) all assert "outside a git repo" behavior and fail only because this review sandbox's own TMPDIR resolves inside the open-mercato/cezar checkout (an artifact of this environment, not the PR); re-ran each failing test in isolation with TMPDIR=/tmp/… and all 6 pass. Not a PR defect. |
npm run test:unit |
✅ PASS | 36/36 |
npm run build |
✅ PASS | check:pack ok, 515 files |
npm run test:package |
✅ PASS | 16/16 |
CI pending: license/cla on this head — not yet signed. Required CI and QA approval still gate merge. A follow-up will report the CI result.
💥 Breaking Changes
capabilities.automationsflips from opt-in (CEZ_AUTOMATIONS=1) to on-by-default (CEZ_AUTOMATIONS !== '0') — deliberate, owner-approved 2026-09-14, correctly documented inBACKWARD_COMPATIBILITY.mdandAGENTS.md, and protected by a boot re-baseline that prevents any pre-existing enabled poll from bursting a backlog on upgrade. The one gap is procedural, not behavioral: no CHANGELOG.md entry records the flip (blocker above) — the doc's own compatibility rule requires one for any 0.x breaking change.- Every other reviewed contract surface (
automation-schedule.ts,zoned-time.ts,RunRecord.automationTrigger, the kind-aware routes) is additive-only and matchesBACKWARD_COMPATIBILITY.mdexactly.
🧪 Test Coverage
Strong overall (DST daily/weekly/weekdays transitions, catch-up/skip/auto-pause boundaries, kind-switch request bodies, capability-flip default/opt-out/no-op, calendar navigation) but with the specific gaps named above: the same-automation-id concurrent-write race, the boot-path wiring of the backlog-prevention re-baseline, the two Copy-as-CLI round-trip bugs, the hours-shape DST spring-forward case, and the deleted capabilities.test.ts coverage for dispatch/usage-presentation flags.
|
🤖
|
- security: shell-quote --workflow/--runner/--model in "Copy as CLI" (automation-cli.ts) so a workflow/model name reachable from a cross-project template or the "automation from a prompt" flow cannot break out of the printed shell command; also escape `!` against bash history expansion. - correctness: emit --no-autonomous when a saved automation has autonomous: false, so Copy as CLI round-trips it instead of silently recreating an autonomous automation. - docs: add the CHANGELOG.md "Breaking" entry the default-on flip requires under this repo's own BACKWARD_COMPATIBILITY.md rule. - perf: lazy-load AutomationsRoute (routes.tsx) to match every other comparably-sized route in this file, now that automations are on by default. - concurrency: AutomationStore.setState now re-reads the target id's own state fresh from disk before merging, not just other ids', so two processes racing on the same automation id (e.g. the loser of a launch lease still advancing its own nextRunAt) can no longer clobber the winner's post-launch state. Updated every call site and added a same-id race regression test. - tests: restore the two capabilities.test.ts suites (dispatch fuzz coverage, usage-presentation matrix) this PR had unrelatedly deleted; add a real boot-path integration test for rebaselineIdleAutomations (the default-flip's backlog-prevention brake) via startServer(); add unit coverage for the two Copy-as-CLI bugs above; fix "every 1 hours" pluralization in scheduleLabel with a test case. Addresses the review at #985 (comment)
- security: shell-quote --workflow/--runner/--model in "Copy as CLI" (automation-cli.ts) so a workflow/model name reachable from a cross-project template or the "automation from a prompt" flow cannot break out of the printed shell command; also escape `!` against bash history expansion. - correctness: emit --no-autonomous when a saved automation has autonomous: false, so Copy as CLI round-trips it instead of silently recreating an autonomous automation. - docs: add the CHANGELOG.md "Breaking" entry the default-on flip requires under this repo's own BACKWARD_COMPATIBILITY.md rule. - perf: lazy-load AutomationsRoute (routes.tsx) to match every other comparably-sized route in this file, now that automations are on by default. - concurrency: AutomationStore.setState now re-reads the target id's own state fresh from disk before merging, not just other ids', so two processes racing on the same automation id (e.g. the loser of a launch lease still advancing its own nextRunAt) can no longer clobber the winner's post-launch state. Updated every call site and added a same-id race regression test. - tests: restore the two capabilities.test.ts suites (dispatch fuzz coverage, usage-presentation matrix) this PR had unrelatedly deleted; add a real boot-path integration test for rebaselineIdleAutomations (the default-flip's backlog-prevention brake) via startServer(); add unit coverage for the two Copy-as-CLI bugs above; fix "every 1 hours" pluralization in scheduleLabel with a test case. Addresses the review at #985 (comment)
🔍 Re-review: feat(automations): scheduled triggers, default-on, redesigned surface, creation from a promptVerdict✅ approve — every blocker and major from the prior review is fixed and verified (typecheck, full test suite, build, package all green). Only minors/nits remain, listed below for the author to pick up at will. What changed since the prior review (commit
|
| Command | Status | Evidence |
|---|---|---|
npm run typecheck |
✅ PASS | clean across contract/client/server/web |
npm test |
✅ PASS | 6934/6934 (run with a real /tmp TMPDIR; this review sandbox's own TMPDIR resolves inside the checkout, which the prior review's validation table already flagged as environment noise, not a PR defect) |
npm run test:unit |
✅ PASS | 36/36 |
npm run build |
✅ PASS | check:pack ok, 520 files |
npm run test:package |
✅ PASS | 16/16 |
CI pending: Unit, build, E2E, and package and license/cla on the new head (c7399bd6). Required CI and QA approval still gate merge. A follow-up will report the CI result.
|
🤖 |
📦 npm preview published —
|
c7399bd to
ca836ad
Compare
|
Two follow-ups from the owner's review, pushed as
🤖 Generated with Claude Code |
…olls Owner asks from the PR review (2026-09-15): no dollar figures on the Automations screens for now — the spent stat, the Cost 7d column and the cost cells of the log and the last-run card sit behind one AUTOMATION_COST_VISIBLE flag (the server keeps answering them); and the Day view shows the enabled GitHub polls the way the Week view does, as a band above the hour grid and as agenda rows, since a poll has no hour but is running that day. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
c334768 to
f41382e
Compare
Stamps the release set (contract, api-client, cezar, web, alias-cezar) and the lockfile 0.10.1 -> 0.11.0, rewrites the intra-release ^0.10.1 ranges to ^0.11.0, and cuts the 0.11.0 CHANGELOG.md entry for the 18 PRs merged since v0.10.1. Minor bump with one breaking change: automations flip back to on by default (#985), reversing the CEZ_AUTOMATIONS=1 opt-in from #802. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GegafinbvuqMr956RzSwvS
Stamps the release set (contract, api-client, cezar, web, alias-cezar) and the lockfile 0.10.1 -> 0.11.0, rewrites the intra-release ^0.10.1 ranges to ^0.11.0, and cuts the 0.11.0 CHANGELOG.md entry for the 18 PRs merged since v0.10.1. Minor bump with one breaking change: automations flip back to on by default (#985), reversing the CEZ_AUTOMATIONS=1 opt-in from #802. Claude-Session: https://claude.ai/code/session_01GegafinbvuqMr956RzSwvS Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Summary
The automations redesign (spec
.ai/specs/2026-09-14-automations-redesign.md, design export under.ai/specs/assets/automations-redesign/): a second trigger kind — a schedule (every day, weekdays, one weekday, every N hours, in the cockpit's own zone) — beside the shipped GitHub poll; automations on by default (CEZ_AUTOMATIONS=0opts out — a breaking flip of the #801 opt-in, owner-approved 2026-09-14 and recorded in AGENTS.md § Zero config andBACKWARD_COMPATIBILITY.md); the Automations surface rebuilt to the design from named primitives; and the "create an automation from a prompt" patch (spec2026-09-13-automations-from-prompt.md) landed on top with both kinds.The spec went through an independent architectural review before any code; four of its findings changed the design (details in the spec's history and
.ai/runs/2026-09-14-automations-redesign.md).What lands
packages/contract/src/automation-schedule.ts(four bounded shapes,cronOf/parseCron, DST-safeoccurrencesBetween/nextOccurrence) andzoned-time.ts(moved out ofcore/usage-limit.ts, which now shares it);kind,schedule,task.dispatch, new log results,timeZone/stats/per-row tallies onGET /automations, the log'srunsmap,automationRunResponseSchema,automationTemplatesResponseSchema; the new optionalRunRecord.automationTrigger(automationuntouched, so a downgrade keeps every run).automations/schedule-runner.ts: one receipt per occurrence, the age rule (on time →scheduled; late within a day → ONEcatch-upfor the latest miss; older →skipped),nextRunAtadvanced frommax(occurrence, now)so a laptop asleep for days never bursts, auto-pause after three launch failures, a held lease or a duplicate never counted.scheduler.tsarms one timer for both kinds; every registered project gets a handle,githubonly for a github.com remote.store.setStateis read-modify-write so two cockpits converge.POST /automations/:id/run(a schedule fired by hand, paused or not), kind-awarecheck/retry,GET /workspace/automation-templates; the default flip with a boot re-baseline of any poll left enabled and idle longer than its lookback, so the flip can never launch a backlog. Inventory updated inBACKWARD_COMPATIBILITY.md.Chip,Segmented,Kbd,BranchChip,Card flush; the list with this-week stats, row actions and the next-runs rail; Week and Day calendars; the editor with a template palette (built-in + other projects), schedule/GitHub fields, the composer's own run-as pills, the dispatch row, a next-five-runs preview and Copy as CLI; the log with nested dispatch children. The Automations nav item followscapabilities.automationsalone — a schedule needs no GitHub remote.cez automation add(flag form;--cronaccepts the four shapes, anything else exits 2 pointing at the JSON form) andcez automation run; the schema reference, the always-on prompt part and the built-in skill cover both kinds..env.example, AGENTS.md exception,BACKWARD_COMPATIBILITY.md(§1 CLI, §2 routes, new default-on section), run notes.Verified
npm run typecheckclean across all four packages;npm test377 files / 6825 tests;npm run test:unit35;npm run build+test:packageok.packages/web/e2e/automations.e2e.ts): default-on sidebar and empty state; schedule created from a template → run by hand → provenance on the run →manualrow in the log → enabled → block in the week view → listed in the next-runs rail → paused from the row → edit header with the last-run card; GitHub poll created paused → preview → baseline → both logged. Phone sweep at 390×844 for the list and the editor.Design fidelity
Captures at 1440×900 from the e2e run, next to the export's screenshots (
design-01…11.jpgin the spec assets):.ai/qa/artifacts_e2e/automations-list-paused.pngautomations-next-runs-rail.pngautomations-week.png,automations-day.pngautomations-editor-new-templates.png,-new-schedule.png,-new-github.png,-edit.pngautomations-log.pngRegenerate with
npm run test:e2e.Not in this PR (deliberately)
New GitHub events (
review_requested,release.published), a repo-committed definition format, per-run budgets outside dispatch, areviewChildfield on the dispatch intent, full cron expressions, automations while the server is stopped. Owner decisions Q1–Q10 are in the spec's "Resolved decisions" table.Review notes
capabilities.automationsisCEZ_AUTOMATIONS !== '0'.=1is accepted and changes nothing. The scheduler starts at boot but arms a timer only for an automation the user enabled.kindand parses as a poll; nothing on disk is rewritten until the next edit. A pre-redesign cezar ignoreskind: 'schedule'definitions as invalid (one warning) and never fires them.task.dispatchis stored as given and ignored, never refused, on a cockpit with dispatch off — the same precedentPOST /runssets.🤖 Generated with Claude Code