# Gap Card — S20 Automation Builder > UX-refactor planning artifact. Execution model: **in-place incremental refactor** of > `apps/web` + targeted backend extensions. Mockups are directional (PRD §24); PRD acceptance > criteria win. Every claim is grounded in a real file path below. > > Sources: PRD §12.10 + §16.10 (`docs/Waggle_OS_UX_Refactor_Master_Handoff_Package/Waggle_OS_UX_Refactor_PRD.md`), > Blueprint screen 20 (`_blueprint_extracted.txt:423-429`), mockup > `Waggle_OS_Handoff_Assets/screens_18_21_builders_and_marketplace.png`, baseline inventories under > `docs/ux-refactor/_inventory/`, backend-map `docs/backend-map/sections/03f-api-realtime-ops.md`. --- ## 1. Screen & purpose A 4-step **stepper** builder that lets a user create a scheduled or event-driven workflow ("automation"). PRD §12.10 / Blueprint screen 20: *"Create scheduled or event-driven workflow. Choose trigger/condition/actions/agent/notification, test, activate."* PRD §12.10 fields (line 605): `name, trigger, condition, actions, agent, notification, schedule, workspace, status`. Builder steps (PRD line 604): **Trigger → Condition → Actions → Review & Activate**. This is the *create/edit* surface; the *list/run/pause/logs* surface is the sibling **Automation Center** (screen 11, PRD §12.10 tabs Overview/Running/Scheduled/Triggers/History/Logs) — scoped in its own card, but they share the same backend (cron) and types. Mockup (directional, panel labelled "20. Automation Builder", top-right of `screens_18_21_builders_and_marketplace.png`): left rail = step list (Trigger/Condition/Actions/ Review); center = config form with a **Trigger** block (schedule vs event), a **Condition** block, an **Actions** list, an **Agent** selector and a **Notification** target; footer = Test + Activate buttons. --- ## 2. Required states (PRD/Blueprint) PRD §14.6 automation lifecycle states: `Draft, Scheduled, Running, Success, Failed, Paused, Awaiting approval, Disabled`. Blueprint screen-20 states (`_blueprint_extracted.txt:428-429`): **Draft; test fail; active; scheduled; approval needed.** Builder-screen states (the create flow itself), composed with PRD §14.1 global states: - **Draft / editing** — stepper in progress, per-step validation (e.g. invalid cron expr, no action chosen). - **Test running / test pass / test fail** — dry-run a draft before activating (PRD line 604 "test"). - **Activating → Scheduled/Active** — on save the automation appears in Automation Center + Home overnight summary (PRD line 607, 611). - **Approval required** — an automation whose actions touch an elevated/risky capability must surface an approval prompt (PRD §17.3 "Automations can only run actions allowed by the user/team role"; PRD line 607 "risky automations surface in Home"). - **Loading / Error / Offline / Permission-denied** — global states (PRD §14.1). Offline: degrade gracefully, keep draft local. --- ## 3. Current state in repo **Disposition: `rework`** (promote the existing cron surface into the Trigger/Actions skeleton; the Condition step + event-triggers + test/approval are net-new but build on cron — no new store). Current implementation is the **cron** surface, not an "Automation Builder": | Layer | File | What it does today | |---|---|---| | Frontend app | `apps/web/src/components/os/apps/ScheduledJobsApp.tsx` | Single-screen "Scheduled Jobs" manager (NOT a stepper). Inline create form with 4 fields: name, **jobType** (`` + custom cron), **outputChannel** (`log`/`telegram`). List rows: enable/disable toggle, run-now (`Play`), delete. `:55` create, `:93` toggle, `:102` delete, `:112` trigger. No condition, no agent picker, no test, no review step. | | Form helpers | `apps/web/src/lib/cron-presets.ts` | `CRON_SCHEDULE_PRESETS` (6 cadences), `CRON_JOB_TYPES` (6 types), `describeCronExpr` / `isPlausibleCronExpr` cron→English. Reusable as-is for the Trigger step. | | Adapter | `apps/web/src/lib/adapter.ts:815-845` | `getCronJobs`, `createCronJob`, `updateCronJob`, `deleteCronJob`, `triggerCronJob` → `/api/cron*`. | | FE type | `apps/web/src/lib/types.ts:230-238` | `CronJob { id, name, schedule, workspaceId, enabled, lastRun?, nextRun? }` — **lossy**: drops `jobType`, `jobConfig`, `createdAt`; renames `cronExpr`→`schedule`, `nextRunAt`→`nextRun`. No `trigger`/`condition`/`actions`/`agent`/`notification`/`status` (the PRD §15/§12.10 automation shape). | | Route | `packages/server/src/local/routes/cron.ts` | Full CRUD + `POST /api/cron/:id/trigger` (auto-enables on run, `:188`). | | Store | `packages/core/src/cron-store.ts` | `CronStore` over `.mind`: `cron_schedules` (`:71`), `cron_execution_history` (`:88`), `notifications` (`:104`). Schedule row: `name, cron_expr, job_type, job_config, workspace_id, enabled, last_run_at, next_run_at`. **No trigger-type, condition, or actions columns** — `job_config` is a free JSON blob. | | Scheduler | `packages/server/src/local/cron.ts` | `LocalScheduler` — 60 s tick, `getDue()` poll, `executeJob()` for manual trigger, auto-disable after 5 consecutive failures (`MAX_CONSECUTIVE_FAILURES`), `onJobComplete` notify callback. **Time-driven only.** | | Executor (the real "actions") | `packages/server/src/local/index.ts:1379-1751` | `new LocalScheduler(cronStore, async (schedule) => switch(schedule.job_type){…})`. Cases: `memory_consolidation` (`:1381`, incl. `action:'index_reconcile'` marketplace sync), `workspace_health` (`:1504`), `proactive` (`:1525`, sub-actions morning_briefing/stale_workspace_check/task_reminder/capability_suggestion `:1561-1582`), `prompt_optimization` (`:1590`), `agent_task` (`:1722`, runs a `jobConfig.prompt` in a workspace), `monthly_assessment`. | | History route | registered in `notifications.ts` | `GET /api/cron/:id/history` (backend-map `03f:147`) → execution rows. | **Grep confirmation:** no `Automation`/`AutomationBuilder` component, no event-trigger code, no `condition` field. The 13 frontend hits for "Automation|trigger|condition" are the word "trigger" used in unrelated contexts (`triggerCronJob`, MCP triggers, marketplace) — confirmed none is an automation builder. (`ScheduledJobsApp.tsx` is the only real match.) **Mental model match:** what the user calls "trigger" today is **only a cron schedule** (time). What the user calls "actions" today is **a single `jobType`** chosen from a fixed catalog (one action per job). There is **no condition, no multi-action sequence, no per-automation agent binding (except via `agent_task` prompt), and no event triggers.** --- ## 4. Frontend work **New components (`apps/web/src/components/os/apps/automations/`):** - `AutomationBuilder.tsx` — 4-step stepper (reuse the **Builder stepper** DS pattern from Agent/Skill builders — PRD §19.1; align with `CreateAgentForm.tsx` in `apps/web/src/components/os/apps/agents/`). Owns draft state `{ name, trigger, condition, actions[], agentId?, notification, schedule, workspaceId, status:'draft' }`; submits via adapter (see §5). - `TriggerStep.tsx` — radio: **Schedule** (reuse `cron-presets.ts` preset/custom `