echo "SUPABASE_URL=$SUPABASE_URL" && echo "SUPABASE_PROJECT_REF=$SUPABASE_PROJECT_REF" && echo "SUPABASE_DB_URL=$SUPABASE_DB_URL" | head -c 200
SUPABASE_URL=https://<ref>.supabase.co SUPABASE_PROJECT_REF=<ref> SUPABASE_DB_URL=<redacted:SUPABASE_DB_URL>
psql "$SUPABASE_DB_URL" -c "SELECT table_name FROM information_schema.tables WHERE table_schema='public';"
table_name ------------------ signups webhook_receipts (2 rows)
psql "$SUPABASE_DB_URL" -c "\d public.signups" && psql "$SUPABASE_DB_URL" -c "\d public.webhook_receipts"
Table "public.signups"
Column | Type | Collation | Nullable | Default
------------+--------------------------+-----------+----------+----------------------------------
id | bigint | | not null | generated by default as identity
email | text | | not null |
plan | text | | not null | 'free'::text
created_at | timestamp with time zone | | not null | now()
Indexes:
"signups_pkey" PRIMARY KEY, btree (id)
Table "public.webhook_receipts"
Column | Type | Collation | Nullable | Default
-------------+--------------------------+-----------+----------+----------------------------------
id | bigint | | not null | generated by default as identity
received_at | timestamp with time zone | | not null | now()
payload | jsonb | | not null |
Indexes:
"webhook_receipts_pkey" PRIMARY KEY, btree (id)
# Check if pg_net extension is available psql "$SUPABASE_DB_URL" -c "SELECT * FROM pg_extension WHERE extname='pg_net';"
oid | extname | extowner | extnamespace | extrelocatable | extversion | extconfig | extcondition -----+---------+----------+--------------+----------------+------------+-----------+-------------- (0 rows)
# Check available extensions for http/networking
psql "$SUPABASE_DB_URL" -c "SELECT * FROM pg_available_extensions WHERE name IN ('pg_net', 'http', 'pg_http', 'pgsql-http', 'supabase');"name | default_version | installed_version | comment --------+-----------------+-------------------+---------------------------------------------------------------------------- http | 1.6 | | HTTP client for PostgreSQL, allows web page retrieval inside the database. pg_net | 0.20.4 | | Async HTTP (2 rows)
psql "$SUPABASE_DB_URL" -c "CREATE EXTENSION IF NOT EXISTS pg_net;"
CREATE EXTENSION
# Check what SUPABASE_SERVICE_ROLE_KEY looks like (just first/last few chars)
echo "Length: ${#SUPABASE_SERVICE_ROLE_KEY}"
echo "First 30: ${SUPABASE_SERVICE_ROLE_KEY:0:30}"
echo "Last 10: ${SUPABASE_SERVICE_ROLE_KEY: -10}"Length: 219 First 30: eyJhbGciOiJIUzI1NiIsInR5cCI6Ik Last 10: Z49JeloS8w
psql "$SUPABASE_DB_URL" -c "SELECT proname, pronargs, prosrc FROM pg_proc WHERE proname LIKE '%http%' AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'net');"
proname | pronargs | prosrc
------------------------+----------+---------------------------------------------------------------------------------------------------------
http_get | 4 | +
| | declare +
| | request_id bigint; +
| | params_array text[]; +
| | begin +
| | select coalesce(array_agg(net._urlencode_string(key) || '=' || net._urlencode_string(value)), '{}')+
| | into params_array +
| | from jsonb_each_text(params); +
| | +
| | -- Add to the request queue +
| | insert into net.http_request_queue(method, url, headers, timeout_milliseconds) +
| | values ( +
| | 'GET', +
| | net._encode_url_with_params_array(url, params_array), +
| | headers, +
| | timeout_milliseconds +
| | ) +
| | returning id +
| | into request_id; +
| | +
| | perform net.wake(); +
| | +
| | return request_id; +
| | end +
| |
http_post | 5 | +
| | declare psql "$SUPABASE_DB_URL" -c "SELECT proname, pronargs, prosrc FROM pg_proc WHERE proname LIKE '%http%' AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'net') ORDER BY proname;"
proname | pronargs | prosrc
------------------------+----------+---------------------------------------------------------------------------------------------------------
_http_collect_response | 2 | +
| | declare +
| | rec net._http_response; +
| | req_exists boolean; +
| | begin +
| | +
| | if not async then +
| | perform net._await_response(request_id); +
| | end if; +
| | +
| | select * +
| | into rec +
| | from net._http_response +
| | where id = request_id; +
| | +
| | if rec is null or rec.error_msg is not null then +
| | -- The request is either still processing or the request_id provided does not exist +
| | +
| | -- TODO: request in progress is indistinguishable from request that doesn't exist +
| | +
| | -- No request matching request_id found +
| | return ( +
| | 'ERROR', +
| | coalesce(rec.error_msg, 'request matching request_id not found'), +
| | null +
| | )::net.http_response_result; +
psql "$SUPABASE_DB_URL" -c "SELECT pg_get_functiondef('net.http_post'::regproc);" 2>&1 | head -60 pg_get_functiondef
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION net.http_post(url text, body jsonb DEFAULT '{}'::jsonb, params jsonb DEFAULT '{}'::jsonb, headers jsonb DEFAULT '{"Content-Type": "application/json"}'::jsonb, timeout_milliseconds integer DEFAULT 5000)+
RETURNS bigint +
LANGUAGE plpgsql +
AS $function$ +
declare +
request_id bigint; +
params_array text[]; +
content_type text; +
begin +
+
-- Exctract the content_type from headers +
select +
header_value into content_type +
from +
jsonb_each_text(coalesce(headers, '{}'::jsonb)) r(header_name, header_value) +
where psql "$SUPABASE_DB_URL" -c "SELECT pg_get_functiondef('net.http_post'::regproc);" 2>&1 pg_get_functiondef
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION net.http_post(url text, body jsonb DEFAULT '{}'::jsonb, params jsonb DEFAULT '{}'::jsonb, headers jsonb DEFAULT '{"Content-Type": "application/json"}'::jsonb, timeout_milliseconds integer DEFAULT 5000)+
RETURNS bigint +
LANGUAGE plpgsql +
AS $function$ +
declare +
request_id bigint; +
params_array text[]; +
content_type text; +
begin +
+
-- Exctract the content_type from headers +
select +
header_value into content_type +
from +
jsonb_each_text(coalesce(headers, '{}'::jsonb)) r(header_name, header_value) +
where # Test the receiver function exists
curl -s -o /dev/null -w "%{http_code}" "${SUPABASE_URL}/functions/v1/hook-recorder" -H "Authorization: Bearer ${SUPABASE_ANON_KEY}" -X POST -H "Content-Type: application/json" -d '{"test": true}'200
psql "$SUPABASE_DB_URL" <<'EOF'
-- Create the trigger function
CREATE OR REPLACE FUNCTION public.webhook_signups_insert()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
DECLARE
url text;
body jsonb;
headers jsonb;
request_id bigint;
BEGIN
url := 'https://<ref>.supabase.co/functions/v1/hook-recorder';
body := jsonb_build_object(
'email', NEW.email,
'plan', NEW.plan
);
headers := jsonb_build_object(
'Content-Type', 'application/json',
'Authorization', 'Bearer <jwt:service_role>'
);
-- Fire async HTTP POST via pg_net
request_id := net.http_post(
url := url,
body := body,
headers := headers,
timeout_milliseconds := 5000
);
-- Log the request_id for debugging (optional)
RAISE LOG 'pg_net request_id % fired for signup id=% email=% plan=%', request_id, NEW.id, NEW.email, NEW.plan;
RETURN NEW;
END;
$$;
-- Attach trigger to signups table
DROP TRIGGER IF EXISTS trg_webhook_signups_insert ON public.signups;
CREATE TRIGGER trg_webhook_signups_insert
AFTER INSERT ON public.signups
FOR EACH ROW
EXECUTE FUNCTION public.webhook_signups_insert();
EOFCREATE FUNCTION DROP TRIGGER CREATE TRIGGER
NOTICE: trigger "trg_webhook_signups_insert" for relation "public.signups" does not exist, skipping
psql "$SUPABASE_DB_URL" <<'EOF'
CREATE OR REPLACE FUNCTION public.webhook_signups_insert()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
DECLARE
url text;
body jsonb;
headers jsonb;
request_id bigint;
BEGIN
url := 'https://<ref>.supabase.co/functions/v1/hook-recorder';
body := jsonb_build_object(
'email', NEW.email,
'plan', NEW.plan,
'id', NEW.id,
'created_at', NEW.created_at
);
headers := jsonb_build_object(
'Content-Type', 'application/json',
'Authorization', 'Bearer ' || current_setting('app.settings.service_role_key')
);
-- Fire async HTTP POST via pg_net
request_id := net.http_post(
url := url,
body := body,
headers := headers,
timeout_milliseconds := 5000
);
RAISE LOG 'pg_net request_id % fired for signup id=% email=% plan=%', request_id, NEW.id, NEW.email, NEW.plan;
RETURN NEW;
END;
$$;
EOFCREATE FUNCTION
# Create the function with the real service role key
psql "$SUPABASE_DB_URL" -c "
CREATE OR REPLACE FUNCTION public.webhook_signups_insert()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS \$\$
DECLARE
url text;
body jsonb;
headers jsonb;
request_id bigint;
BEGIN
url := 'https://<ref>.supabase.co/functions/v1/hook-recorder';
body := jsonb_build_object(
'email', NEW.email,
'plan', NEW.plan,
'id', NEW.id,
'created_at', NEW.created_at
);
headers := jsonb_build_object(
'Content-Type', 'application/json',
'Authorization', 'Bearer ${SUPABASE_SERVICE_ROLE_KEY}'
);
-- Fire async HTTP POST via pg_net
request_id := net.http_post(
url := url,
body := body,
headers := headers,
timeout_milliseconds := 5000
);
RAISE LOG 'pg_net request_id % fired for signup id=% email=% plan=%', request_id, NEW.id, NEW.email, NEW.plan;
RETURN NEW;
END;
\$\$;
"CREATE FUNCTION
# First check current state of webhook_receipts psql "$SUPABASE_DB_URL" -c "SELECT * FROM public.webhook_receipts;"
id | received_at | payload
----+------------------------------+----------------
2 | 2026-07-24 06:49:03.76397+00 | {"test": true}
(1 row)
psql "$SUPABASE_DB_URL" -c "INSERT INTO public.signups (email, plan) VALUES ('e2e-test@example.com', 'pro') RETURNING *;"id | email | plan | created_at ----+----------------------+------+------------------------------- 1 | e2e-test@example.com | pro | 2026-07-24 06:49:50.126258+00 (1 row) INSERT 0 1
# Give pg_net a moment to deliver, then check receipts sleep 3 psql "$SUPABASE_DB_URL" -c "SELECT * FROM public.webhook_receipts ORDER BY id DESC LIMIT 5;"
id | received_at | payload
----+-------------------------------+-------------------------------------------------------------------------------------------------------------
3 | 2026-07-24 06:49:50.434306+00 | {"id": 1, "plan": "pro", "email": "e2e-test@example.com", "created_at": "2026-07-24T06:49:50.126258+00:00"}
2 | 2026-07-24 06:49:03.76397+00 | {"test": true}
(2 rows)
# Second test - different plan, different email
psql "$SUPABASE_DB_URL" -c "INSERT INTO public.signups (email, plan) VALUES ('another@example.com', 'enterprise') RETURNING *;"
sleep 3
psql "$SUPABASE_DB_URL" -c "SELECT * FROM public.webhook_receipts ORDER BY id DESC LIMIT 5;" id | email | plan | created_at
----+---------------------+------------+-------------------------------
2 | another@example.com | enterprise | 2026-07-24 06:50:05.161823+00
(1 row)
INSERT 0 1
id | received_at | payload
----+-------------------------------+-------------------------------------------------------------------------------------------------------------------
4 | 2026-07-24 06:50:05.313528+00 | {"id": 2, "plan": "enterprise", "email": "another@example.com", "created_at": "2026-07-24T06:50:05.161823+00:00"}
3 | 2026-07-24 06:49:50.434306+00 | {"id": 1, "plan": "pro", "email": "e2e-test@example.com", "created_at": "2026-07-24T06:49:50.126258+00:00"}
2 | 2026-07-24 06:49:03.76397+00 | {"test": true}
(3 rows)
curl -s "${SUPABASE_URL}/rest/v1/signups" \
-H "apikey: ${SUPABASE_ANON_KEY}" \
-H "Authorization: Bearer ${SUPABASE_ANON_KEY}" \
-H "Content-Type: application/json" \
-d '{"email": "api-user@example.com", "plan": "free"}'sleep 3 psql "$SUPABASE_DB_URL" -c "SELECT * FROM public.signups ORDER BY id DESC LIMIT 3;" echo "---" psql "$SUPABASE_DB_URL" -c "SELECT * FROM public.webhook_receipts ORDER BY id DESC LIMIT 5;"
id | email | plan | created_at
----+----------------------+------------+-------------------------------
3 | api-user@example.com | free | 2026-07-24 06:50:13.722081+00
2 | another@example.com | enterprise | 2026-07-24 06:50:05.161823+00
1 | e2e-test@example.com | pro | 2026-07-24 06:49:50.126258+00
(3 rows)
---
id | received_at | payload
----+-------------------------------+-------------------------------------------------------------------------------------------------------------------
5 | 2026-07-24 06:50:13.870153+00 | {"id": 3, "plan": "free", "email": "api-user@example.com", "created_at": "2026-07-24T06:50:13.722081+00:00"}
4 | 2026-07-24 06:50:05.313528+00 | {"id": 2, "plan": "enterprise", "email": "another@example.com", "created_at": "2026-07-24T06:50:05.161823+00:00"}
3 | 2026-07-24 06:49:50.434306+00 | {"id": 1, "plan": "pro", "email": "e2e-test@example.com", "created_at": "2026-07-24T06:49:50.126258+00:00"}
2 | 2026-07-24 06:49:03.76397+00 | {"test": true}
(4 rows)
7 earlier narration turn(s) are in the raw transcript.
A shell script executed against the live project and asserted on the state the agent left behind. No model judged another model.
Raw transcript · Task definition and verifier · Every attempt