This repository contains a starter example for pgflow, a workflow orchestration system that runs inside your Supabase Postgres database. It shows how to classify HackerNews posts using OpenAI models.
The example demonstrates how to replay historical inputs against modified workflow steps - useful for testing how changes to prompts, models, or logic affect outputs without re-fetching source data. This makes it easy to iterate on AI workflows and compare results across different configurations.
For detailed documentation, architecture overview, and advanced usage, see the Full README.
graph TD
Start([Input: HN URL]) --> Item[Fetch Item]
Start --> Comment[Fetch First Comment]
Item --> Classification[AI Classification]
Comment --> Classification
style Start fill:#1e293b,color:#fff
style Item fill:#1e293b,color:#fff
style Comment fill:#1e293b,color:#fff
style Classification fill:#1e293b,color:#fff
Source files: Flow Definition | Original Classify Task | Model-Parametrized Version
cd supabase/functions && cp .env.example .env
# Add: OPENAI_API_KEY, EDGE_WORKER_DB_URL (from supabase status)
npx -y supabase@latest start
npx -y supabase@latest functions serve
Wait 3s for pg_cron to start the worker.
SELECT * FROM pgflow.start_flow(
flow_slug => 'classifyHnItem',
input => jsonb_build_object('url','https://news.ycombinator.com/item?id=45245948')
);
WITH urls AS (
SELECT unnest(ARRAY[
'https://news.ycombinator.com/item?id=45247890',
'https://news.ycombinator.com/item?id=45248802',
'https://news.ycombinator.com/item?id=45223827',
'https://news.ycombinator.com/item?id=45246953',
'https://news.ycombinator.com/item?id=45245948',
'https://news.ycombinator.com/item?id=45243635',
'https://news.ycombinator.com/item?id=45221023',
'https://news.ycombinator.com/item?id=45226938',
'https://news.ycombinator.com/item?id=45246403',
'https://news.ycombinator.com/item?id=45243803'
]) AS url
)
SELECT pgflow.start_flow(
flow_slug => 'classifyHnItem',
input => jsonb_build_object('url', url)
) FROM urls;
-- Recent runs
SELECT flow_slug, status, output->'classification'
FROM pgflow.runs
ORDER BY started_at DESC LIMIT 10;
-- Completed classifications
SELECT input->>'url', output->'classification'
FROM pgflow.runs
WHERE flow_slug = 'classifyHnItem' AND status = 'completed';
→ Monitor flow execution (pgflow.dev)
SELECT pgflow.prune_data_older_than(make_interval(days => 0));
npm run compare
# or
npm run compare:limit -- --limit 10
The compare script demonstrates pgflow's replay capability with no magic - it simply:
- Loads past run inputs with a single SQL query
- Calls the classification step directly with those inputs
- Compares outputs from different models (gpt-5-nano/mini/gpt5)
This lets you test how prompt or model changes affect outputs without re-fetching data or modifying the database.