Repository navigation
feat: watch an agent build a workflow live - #88
Conversation
- workflow_drafts holds what an agent builds, apart from workflow_definitions - agent_activity records the nodes each agent touches and when - a node change set names added, changed and removed nodes and edges - every signal notifies the agent channel; setup progress does too - migration 0035 adds both tables and the reduce agent motion setting
- validate_workflow keeps each checked workflow as a draft when the agent may manage workflows - apply_workflow saves as before and promotes the draft - begin_workflow_work opens a draft at once and returns the id to write with - finish_workflow_work releases listed nodes, or every node and the session
- the SSE stream listens on agent and sends each change to viewers who can see the repo - setup progress goes only to the person whose run it is
- drafts show on the workflows page with a Draft badge, Save and Discard - a dithered blue outline in the new agent token marks the card and each node an agent works on - the canvas animates each change as it lands: nodes fade in, edges draw in, removed steps fade out - the editor header names the agent with a 3 by 2 activity mark - one shared event stream feeds the Query cache; the setup card stops polling while it is open - account settings can reduce agent animations, and the OS setting is honoured
- the demo head serves the event stream from embedded Postgres through the api's message builder - POST /api/dev/agent-sim plays an agent building Close stale PRs through the real services - the outline sizes to the border box and is not capped by the canvas max width - the card names the working agent under the title
| definition: input.definition ?? input.draft.definition, | ||
| revision: changed ? input.draft.revision + 1 : input.draft.revision, | ||
| lastChange: changed ? input.change : input.draft.lastChange, | ||
| updatedAt: input.now, | ||
| }) | ||
| .where(eq(workflowDrafts.id, input.draft.id)); |
There was a problem hiding this comment.
Draft mutations are not serialized per workflow
Medium Severity
If promoteDraft reads revision 1 and an agent successfully saves revision 2 while applyWorkflowDefinition is awaiting its queries, closeDraft overwrites the row with the revision-1 snapshot and marks it promoted. Both callers report success, but the newer work is lost. Initial concurrent signals also both observe no open draft: writeDraft can either discard the other caller's newly inserted draft or fail on workflow_drafts_open_unique. Serialize creation, revision updates, and promotion/discard per repo and definition, using a transaction with appropriate locking or revision/status checks rather than unconditional writes by row ID.
| } | ||
| const next = new EventSource(STREAM_URL); | ||
| source = next; | ||
| next.onopen = () => setConnected(true); |
There was a problem hiding this comment.
Reconnecting the stream does not recover missed state
Medium Severity
During a brief API restart, an agent can finish setup or change/promote a draft while the browser's EventSource is disconnected. Postgres notifications are not replayed, and this onopen handler only changes connection status: neither useLiveWork nor useLiveSetup refetches its queries. Once connected again, AgentSetupCard also disables its fallback polling, so a missed final report can leave the checklist stale indefinitely; non-scheduled workflow views likewise have no periodic recovery. Refetch the subscribed setup and workflow queries when the stream opens or reconnects, or supply a replay/snapshot protocol.
| const nodes = agentNodeTouchesSchema.parse( | ||
| mergeTouches(fresh ? activityTouches(row) : [], input.touches, input.now), | ||
| ); |
There was a problem hiding this comment.
Presence validation rejects otherwise valid workflow node IDs
Medium Severity
A compiled workflow with a 201-character node ID passes workflowDefinitionSchema, whose node IDs are unrestricted z.string() values. saveAgentDraft now writes the draft and then throws here because agentNodeTouchSchema caps IDs at 200 characters; applyAgentWorkflow can similarly commit the saved workflow before touch throws, causing apply_workflow to report failure and abort the remaining definitions despite already saving one. Empty IDs produce the same mismatch. Keep presence compatible with the workflow ID contract, and ensure auxiliary presence validation cannot turn an already committed workflow save into a reported failure.
Brings in CLI push review (propose_workflow_push, get_workflow_push), the Pierre code view, project links and slug workflow keys. - 0035_live_agent_work is regenerated on top of 0034_workflow_push_proposals. The SQL is unchanged and the snapshot now chains from 0034. - MCP lists the union of tools: push review plus begin and finish work. - validate_workflow and apply_workflow match server ids before drafts. - An accepted push review promotes the open draft for each saved workflow.
Each draft mutation (begin, check, apply, promote, discard, finish, push promotion) now runs in one transaction behind a per-workflow advisory lock. Concurrent first signals share one draft, and a promote or discard can no longer overwrite a newer revision. Presence touches use the workflow node id schema, so any id a definition accepts also passes presence, and a touch can never fail a committed save.
Postgres notifications are not replayed, so the stream now tells views to resync when it reconnects or the tab becomes visible again. The workflows list, open workflows, setup card and activity feed refetch on resync. A stream the browser gave up on reopens after a short delay.
…sing Each push entry records the open draft's id and revision when the push is proposed. On accept, under the per-workflow draft lock, the draft is promoted only if it is still that id and revision. A newer draft stays open on the saved workflow, so a person can still save or discard it.
an agent that builds a workflow over the mcp now builds it where you can watch it.
workflow_draftstable, apart fromworkflow_definitions, so nothing that runs workflows can read one. a draft never runsagent_activityrecords which nodes each agent touches (read, write, edit, delete) and whenfinish_workflow_workclears at oncevalidate_workflowkeeps each checked workflow as a draft when the agent may manage workflows (configure scope,workflows:manage, not read only). read-only agents still validate with no draftapply_workflowsaves as before (a new workflow stays off) and promotes the open draftbegin_workflow_workopens an empty draft at once and returns the id to write with;finish_workflow_workreleases listed nodes or all/events/streamlistens on a newagentchannel; work goes to viewers withactivity:readon the repo, setup progress only to the run's owneragentmessages into the Query cache. the home setup card stops polling while the stream is opendither/pixel.ts, one shared 30 fps loop, per action sweep (read and write 1500 ms, edit 1000, delete 800)--agent(oklch 0.637 0.167 254, dark 0.7 0.15 254), used only for agent activityPOST /api/dev/agent-simplays an agent through the real services0035_live_agent_workis additive: two tables anduser.reduce_agent_motiondecisions on the issue's open questions
apply_workflowkeeps saving and promotes the draft, rather than writing drafts by default. the cli's push uses it and keeps workingworkflows:managesaves or discardsproof (local pglite, port 3445): screenshots light and dark and recordings in
/tmp/wf-feedback/live-agent/tests: contracts change set and presence math, db integration on real postgres (drafts never run on any trigger incl. schedules, expiry, promote, discard, live edit keeps the live version running, notify), mcp tools and permissions, sse channel incl. a user without repo access getting nothing, web cache merge, canvas decoration and dither ring
Closes #84