Workflows Engine
Versioned, authored workflow graphs executed node-by-node.
WorkflowsLiveSupabaseNode.js
56runs
What it is
A general workflow engine: versioned graph definitions, run history, and per-node execution records. Triggers fire off a domain-event bus; operator nodes dispatch agent jobs.
Take it with you
The real, committed source behind this system — copy it or download the file. Plus a portable spec of everything on this page.
workflows_schema.sqlsql117 lines
The workflow engine data model — versioned defs, runs, and per-node runs, with RLS. Idempotent DDL.
-- ---------------------------------------------------------------------------
-- Workflow Designer Studio — the engine data model (WFS Phase 1, issue #1109).
--
-- Generalizes the Agents Store job model into a versioned, JSON-defined GRAPH
-- without replacing it. A workflow is a DAG of nodes + edges; a run executes
-- that graph; each node run REUSES the agent_jobs lifecycle (operator nodes
-- queue/drain exactly as today) by linking back to agent_jobs.id.
--
-- workflow_defs — versioned graph definitions (immutable once published;
-- a new edit inserts a new (slug, version) row).
-- workflow_runs — one row per execution of a def@version.
-- workflow_node_runs — per-node execution; operator nodes point at the
-- agent_jobs row the existing drain runs.
--
-- The web app GOVERNS (author/publish/enqueue/approve); the existing GitHub
-- Actions runner EXECUTES operator nodes via agent_jobs — zero new runner code.
--
-- RLS on, NO anon — service-role only. Apply to the MAIN project
-- (diziibeymowzpondeqxz). Additive, idempotent. Reuses iam_set_updated_at().
-- ---------------------------------------------------------------------------
-- --- workflow_defs (the authored graph, versioned) --------------------------
create table if not exists public.workflow_defs (
id uuid primary key default gen_random_uuid(),
slug text not null, -- stable workflow identity (e.g. 'entity-wars.surface')
version integer not null default 1, -- bumps on every published edit; (slug, version) immutable
graph jsonb not null default '{"nodes":[],"edges":[]}'::jsonb,
triggers jsonb not null default '[]'::jsonb, -- [{ type: 'cron'|'event'|'manual'|'webhook', ... }]
enabled boolean not null default false, -- only an enabled def fires on a trigger
created_by text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique (slug, version)
);
comment on table public.workflow_defs is
'WFS: versioned, JSON-defined workflow graphs. Immutable once published — a new edit inserts a new (slug, version). enabled gates trigger firing.';
create index if not exists workflow_defs_slug_idx
on public.workflow_defs (slug, version desc);
create index if not exists workflow_defs_enabled_idx
on public.workflow_defs (enabled, slug);
drop trigger if exists workflow_defs_set_updated_at on public.workflow_defs;
create trigger workflow_defs_set_updated_at
before update on public.workflow_defs
for each row execute function public.iam_set_updated_at();
alter table public.workflow_defs enable row level security;
-- --- workflow_runs (one per execution) --------------------------------------
create table if not exists public.workflow_runs (
id uuid primary key default gen_random_uuid(),
workflow_id uuid not null references public.workflow_defs (id) on delete cascade,
slug text not null, -- denormalized for cheap listing/filtering
version integer not null, -- the def version this run executes (defs are immutable)
status text not null default 'queued'
check (status in ('queued', 'running', 'blocked', 'done', 'failed', 'cancelled')),
trigger_ref text, -- 'manual:<actor>' | 'cron' | 'event:<id>' | 'webhook:<source>'
inputs jsonb not null default '{}'::jsonb,
error text,
queued_at timestamptz not null default now(),
started_at timestamptz,
finished_at timestamptz,
created_by text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
comment on table public.workflow_runs is
'WFS: one row per workflow execution. blocked = paused on a human-gate node (resumes to running on approve). Mirrors the agent_jobs status discipline.';
create index if not exists workflow_runs_workflow_idx
on public.workflow_runs (workflow_id, status, queued_at);
create index if not exists workflow_runs_status_idx
on public.workflow_runs (status, queued_at);
create index if not exists workflow_runs_slug_idx
on public.workflow_runs (slug, queued_at);
drop trigger if exists workflow_runs_set_updated_at on public.workflow_runs;
create trigger workflow_runs_set_updated_at
before update on public.workflow_runs
for each row execute function public.iam_set_updated_at();
alter table public.workflow_runs enable row level security;
-- --- workflow_node_runs (per-node, reuses agent_jobs for operator steps) -----
create table if not exists public.workflow_node_runs (
id uuid primary key default gen_random_uuid(),
run_id uuid not null references public.workflow_runs (id) on delete cascade,
node_id text not null, -- the node's id WITHIN the graph
node_type text not null, -- 'operator' | 'llm' | 'http' | 'human-gate'
status text not null default 'pending'
check (status in ('pending', 'queued', 'running', 'blocked', 'done', 'failed', 'skipped', 'cancelled')),
verdict text check (verdict in ('pass', 'fail', 'risk')), -- operator nodes inherit the agent_jobs verdict
agent_job_id uuid references public.agent_jobs (id) on delete set null, -- the queued/drained job for operator nodes
output jsonb, -- bounded node output handed to downstream ports
error text,
attempts integer not null default 0,
started_at timestamptz,
finished_at timestamptz,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique (run_id, node_id)
);
comment on table public.workflow_node_runs is
'WFS: per-node execution within a workflow_run. Operator nodes link agent_job_id and inherit its verdict — the existing drain runs them, zero new runner code.';
create index if not exists workflow_node_runs_run_idx
on public.workflow_node_runs (run_id);
create index if not exists workflow_node_runs_job_idx
on public.workflow_node_runs (agent_job_id);
drop trigger if exists workflow_node_runs_set_updated_at on public.workflow_node_runs;
create trigger workflow_node_runs_set_updated_at
before update on public.workflow_node_runs
for each row execute function public.iam_set_updated_at();
alter table public.workflow_node_runs enable row level security;
Where it lives
- supabase/workflows_schema.sql
- supabase/domain_events_schema.sql
See it in action
Platform →FAQ
What triggers a workflow?
Producers emit domain events (a game merged, a PR merged, content seeded); workflow triggers consume that stream and spawn runs.
Part of these stacks
Related systems
Want a system like this built for you?Work with me →