v2: workflow templates, backed by plugin-owned definitions - #254
v2: workflow templates, backed by plugin-owned definitions#254xBalbinus wants to merge 1 commit into
Conversation
The workflows page offered nothing but an empty state. Templates are the starting points, ported from the V1 gallery that was removed from main. Architecture, not code, came across. V1 was Workers, D1 and IntegrationPackage with a draft/publish split; v2 is Hono, Postgres and ValetPlugin with one definition row and immutable version snapshots. What survives is the shape: a plugin owns the templates for the integrations it owns, so enabling a plugin adds its templates and disabling one removes them, and a template is installed by the same create path a user's own workflow takes. Eight templates, each drawn from a use case the team actually runs: a nightly memory sweep, a daily triage digest, weekly meeting prep, one instruction over a batch of rows, a daily development digest, a nudge on quiet pull requests, an inbox sweeper, and weekly issue triage. Install is atomic. Everything after the definition row sits in a rollback, so a validation failure or a trigger collision leaves nothing behind, and webhook paths carry a uuid-derived suffix because they are globally unique. A template whose integration is not connected says so instead of offering an install that would fail. WorkflowInputDefinition regains label, placeholder and hidden, so a template declares each input once in the trigger schema and the run form is derived from it rather than duplicated. Verified by running, not by reading: two templates were installed through the real route on an isolated api and driven to settled/completed, and all 52 template paths across every shipped template were resolved against the real template context. Six templates remain unproven at run time because they need live GitHub, Gmail, Linear or Slack credentials. web 808 passing, workflow 303, engine 39, plugin suites 132, api template suites 155, typecheck clean.
There was a problem hiding this comment.
The PR is well-structured with thorough testing and a clean separation of concerns. Two real issues are worth flagging.
-
packages/api/src/workflows/templates.ts:lines 588–608 — TheteamMissingsentinel pattern is load-bearing but fragile. The transaction callback setsteamMissing = trueand returns early to commit an empty transaction, then the caller checks the flag afterward. This works only because the transaction is committed before theawaitresolves. However, the comment says "commits an EMPTY transaction — the check runs before any insert, so there is nothing to roll back," but if a future developer adds any write before theisTeamMembercheck (e.g. to lock a row), the pattern silently commits a partial transaction instead of rolling back. The intent is correct but the pattern is a trap: a thrown error (ortx.rollback()) would be both clearer and safer than returning from inside the callback and checking a flag outside it. At minimum, the comment should say why a throw would also work and why the silent-commit path was chosen over it. -
packages/api/src/workflows/templates.ts:line 624 — The repeat-install naming query useslike(workflowDefinitions.name, \${owned.template.name} (%`)with no escaping of SQLLIKEwildcards inowned.template.name. A template whose name contains%or_(e.g. a future template named "100% automated sweep") will match more rows than intended, producing an inflated count and a wrong suffix on the second install. The template names shipped today are safe, but this is a latent correctness bug. The fix is to escape the name before interpolating it into theLIKE` pattern, or to use a regex match instead.
Created on behalf of Xiangan He xiangan@turnkey.io
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Superseded by #259, which consolidates this branch with five other v2 workstreams. These six touched the same files repeatedly — the wire types, the workflows routes, the integrations surface, and the app migration — so reviewed separately each conflicted with the others and showed a shape that would not survive the next merge. Every commit from this branch is in #259 in full. Closing here; review moves there. |
What
The workflows page offered nothing but "No workflows yet — create one." This adds templates: eight starting points, each owned by the plugin that owns the integrations it calls.
Ported from the V1 gallery (removed from
mainafter it shipped;d3340f19is the surviving copy). The architecture came across, not the code — V1 was Workers/D1/IntegrationPackagewith a draft→publish split; v2 is Hono/Postgres/ValetPluginwith one definition row and immutable version snapshots.The templates
Each is a use case the team actually runs, not an invented demo:
Guards
WorkflowInputDefinitionregainslabel/placeholder/hidden, so a template declares each input once in the trigger schema and the run form derives from it instead of duplicating the list.Test plan
Verified by running, not by reading.
settled/completedthrough the real install route on an isolated api (port 18931, scratch data dir — the dev stack was untouched):batch-over-rowsprocessed 3 rows through an llm judge and a rollup;nightly-memory-sweepcompleted its hygiene pass.{{...}}paths across every shipped template resolved against the real template context, enumerated programmatically rather than by hand. Zero unresolved.Unproven at run time: six templates — the GitHub, Gmail, Linear and Slack ones need live credentials this environment lacks. Their tool contracts are covered by executing the real actions, but no full DAG has been driven for them.
Contract facts verified in code
Worth recording, since two contradict what was previously assumed:
nodes.x.resultand.output(both writecp.result)..dataand.responseare rejected at save time.{text, usage}; with anoutputSchemait yields{text, output, usage}. An orchestrator node is the opposite shape:{sessionId, response, output}.foreachcaps at 100 items by default, is overridable, and reportstruncatedCount.waithas nomodedefault —mode: 'duration'is required, with exactly one legal value.