env | grep -i supabase; echo "---"; which psql supabase curl jq 2>/dev/null; echo "---"; psql --version 2>/dev/null; supabase --version 2>/dev/null
SUPABASE_DB_PASSWORD=<redacted:SUPABASE_DB_PASSWORD> SUPABASE_DB_URL=<redacted:SUPABASE_DB_URL> SUPABASE_URL=https://<ref>.supabase.co SUPABASE_SERVICE_ROLE_KEY=<redacted:SUPABASE_SERVICE_ROLE_KEY> SUPABASE_PROJECT_REF=<ref> SUPABASE_ANON_KEY=<redacted:SUPABASE_ANON_KEY> --- /usr/bin/psql /usr/bin/supabase /usr/bin/curl /usr/bin/jq --- psql (PostgreSQL) 18.4 (Debian 18.4-1.pgdg12+1) 2.75.0
psql "$SUPABASE_DB_URL" -c "\d public.signups" 2>&1 | head -50
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)
psql "$SUPABASE_DB_URL" -c "\d public.webhook_receipts" 2>&1 | head -40; echo "==== extensions ===="; psql "$SUPABASE_DB_URL" -c "select extname, extversion from pg_extension order by extname;" 2>&1
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)
==== extensions ====
extname | extversion
--------------------+------------
pg_stat_statements | 1.11
pgcrypto | 1.3
plpgsql | 1.0
supabase_vault | 0.3.1
uuid-ossp | 1.1
(5 rows)
psql "$SUPABASE_DB_URL" -c "select current_user, current_database();" 2>&1 echo "=== try create pg_net ===" psql "$SUPABASE_DB_URL" -c "create extension if not exists pg_net;" 2>&1
current_user | current_database --------------+------------------ postgres | postgres (1 row) === try create pg_net === CREATE EXTENSION
psql "$SUPABASE_DB_URL" -c "\dn" 2>&1 echo "=== vault schema ===" psql "$SUPABASE_DB_URL" -c "\d vault.*" 2>&1 | head -60
List of schemas
Name | Owner
----------------+-------------------
app | postgres
auth | supabase_admin
extensions | postgres
graphql | supabase_admin
graphql_public | supabase_admin
net | supabase_admin
pgbouncer | pgbouncer
private | postgres
public | pg_database_owner
realtime | supabase_admin
storage | supabase_admin
vault | supabase_admin
(12 rows)
=== vault schema ===
View "vault.decrypted_secrets"
Column | Type | Collation | Nullable | Default
------------------+--------------------------+-----------+----------+---------
id | uuid | | |
name | text | | |
description | text | | |
secret | text | | |
decrypted_secret | text | C | |
key_id | uuid | | |
nonce | bytea | | |
created_at | timestamp with time zone | | |
updated_at | timestamp with time zone | | |
Table "vault.secrets"
Column | Type | Collation | Nullable | Default
-------------+--------------------------+-----------+----------+-----------------------------------
id | uuid | | not null | gen_random_uuid()
name | text | | |
description | text | | not null | ''::text
secret | text | | not null |
key_id | uuid | | |
nonce | bytea | | | vault._crypto_aead_det_noncegen()
created_at | timestamp with time zone | | not null | CURRENT_TIMESTAMP
updated_at | timestamp with time zone | | not null | CURRENT_TIMESTAMP
Indexes:
"secrets_pkey" PRIMARY KEY, btree (id)
"secrets_name_idx" UNIQUE, btree (name) WHERE name IS NOT NULL
Index "vault.secrets_name_idx"
Column | Type | Key? | Definition
--------+------+------+------------
name | text | yes | name
unique, btree, for table "vault.secrets", predicate (name IS NOT NULL)
Index "vault.secrets_pkey"
Column | Type | Key? | Definition
--------+------+------+------------
id | uuid | yes | id
primary key, btree, for table "vault.secrets"
psql "$SUPABASE_DB_URL" -c "select proname, pg_get_function_arguments(oid) from pg_proc where proname in ('create_secret','decrypted_secrets') order by proname;" 2>&1
echo "=== store secret ==="
psql "$SUPABASE_DB_URL" <<'SQL' 2>&1
select vault.create_secret(
secret => current_setting('app.settings.svc_key', true),
name => 'supabase_service_jwt',
description => 'Service role JWT used by pg_net webhook trigger'
);
SQL proname | pg_get_function_arguments
---------------+------------------------------------------------------------------------------------------------------------------------------
create_secret | new_secret text, new_name text DEFAULT NULL::text, new_description text DEFAULT ''::text, new_key_id uuid DEFAULT NULL::uuid
(1 row)
=== store secret ===
ERROR: function vault.create_secret(secret => text, name => unknown, description => unknown) does not exist
LINE 1: select vault.create_secret(
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
psql "$SUPABASE_DB_URL" -v svc_key="'$SUPABASE_SERVICE_ROLE_KEY'" <<'SQL' 2>&1 select vault.create_secret( :svc_key, 'supabase_service_jwt', 'Service role JWT used by pg_net webhook trigger' ); SQL echo "=== verify ===" psql "$SUPABASE_DB_URL" -c "select id, name, description, left(secret,12)||'...' as secret_preview from vault.decrypted_secrets where name='supabase_service_jwt';" 2>&1
create_secret
--------------------------------------
80114a56-aa58-4cf2-922b-a436a13d0bfb
(1 row)
=== verify ===
id | name | description | secret_preview
--------------------------------------+----------------------+-------------------------------------------------+-----------------
80114a56-aa58-4cf2-922b-a436a13d0bfb | supabase_service_jwt | Service role JWT used by pg_net webhook trigger | WifL95bGQFzo...
(1 row)
psql "$SUPABASE_DB_URL" -c "select proname, pg_get_function_arguments(oid), pg_get_function_result(oid) from pg_proc where proname like 'http%' and pronamespace = 'net'::regnamespace order by proname;" 2>&1 echo "=== net schema grants for postgres / check _http_response ===" psql "$SUPABASE_DB_URL" -c "\d net._http_response" 2>&1 | head -20
proname | pg_get_function_arguments | pg_get_function_result
-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------
http_collect_response | request_id bigint, async boolean DEFAULT true | net.http_response_result
http_delete | url text, params jsonb DEFAULT '{}'::jsonb, headers jsonb DEFAULT '{}'::jsonb, timeout_milliseconds integer DEFAULT 5000, body jsonb DEFAULT NULL::jsonb | bigint
http_get | url text, params jsonb DEFAULT '{}'::jsonb, headers jsonb DEFAULT '{}'::jsonb, timeout_milliseconds integer DEFAULT 5000 | bigint
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 | bigint
(4 rows)
=== net schema grants for postgres / check _http_response ===
Unlogged table "net._http_response"
Column | Type | Collation | Nullable | Default
--------------+--------------------------+-----------+----------+---------
id | bigint | | |
status_code | integer | | |
content_type | text | | |
headers | jsonb | | |
content | text | | |
timed_out | boolean | | |
error_msg | text | | |
created | timestamp with time zone | | not null | now()
Indexes:
"_http_response_created_idx" btree (created)
psql "$SUPABASE_DB_URL" <<'SQL' 2>&1
CREATE OR REPLACE FUNCTION public.notify_signup_webhook()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public, net, vault, pg_catalog
AS $$
DECLARE
v_jwt text;
v_url text := 'https://<ref>.supabase.co/functions/v1/hook-recorder';
v_req bigint;
v_row record;
BEGIN
-- Fetch the project JWT (service role key) from the Supabase Vault.
SELECT decrypted_secret
INTO v_jwt
FROM vault.decrypted_secrets
WHERE name = 'supabase_service_jwt';
IF v_jwt IS NULL THEN
RAISE WARNING 'notify_signup_webhook: missing vault secret supabase_service_jwt; skipping webhook.';
RETURN NULL;
END IF;
-- Enqueue one async HTTP POST per inserted row (transition table).
FOR v_row IN SELECT * FROM new_rows LOOP
v_req := net.http_post(
url := v_url,
body := jsonb_build_object(
'email', v_row.email,
'plan', v_row.plan,
'id', v_row.id,
'created_at', v_row.created_at
),
headers := jsonb_build_object(
'Content-Type', 'application/json',
'Authorization', 'Bearer ' || v_jwt
),
timeout_milliseconds := 5000
);
END LOOP;
RETURN NULL;
END;
$$;
SQL
echo "=== create trigger ==="
psql "$SUPABASE_DB_URL" <<'SQL' 2>&1
DROP TRIGGER IF EXISTS trg_signup_webhook ON public.signups;
CREATE TRIGGER trg_signup_webhook
AFTER INSERT ON public.signups
REFERENCING NEW TABLE AS new_rows
FOR EACH STATEMENT
EXECUTE FUNCTION public.notify_signup_webhook();
SQLCREATE FUNCTION === create trigger === NOTICE: trigger "trg_signup_webhook" for relation "public.signups" does not exist, skipping DROP TRIGGER CREATE TRIGGER
TEST_EMAIL="e2e-test-$(date +%s)@example.com"
echo "TEST_EMAIL=$TEST_EMAIL"
psql "$SUPABASE_DB_URL" -c "INSERT INTO public.signups (email, plan) VALUES ('$TEST_EMAIL', 'pro');" 2>&1
echo "=== waiting 8s for async pg_net delivery ==="
sleep 8
echo "=== receipts matching test email ==="
psql "$SUPABASE_DB_URL" -c "SELECT id, received_at, payload->>'email' AS email, payload->>'plan' AS plan FROM public.webhook_receipts WHERE payload->>'email' = '$TEST_EMAIL';" 2>&1TEST_EMAIL=e2e-test-1785035413@example.com INSERT 0 1 === waiting 8s for async pg_net delivery === === receipts matching test email === id | received_at | email | plan ----+-------------------------------+---------------------------------+------ 2 | 2026-07-26 03:10:14.801321+00 | e2e-test-1785035413@example.com | pro (1 row)
echo "=== last pg_net responses (status) ==="
psql "$SUPABASE_DB_URL" -c "SELECT id, status_code, error_msg FROM net._http_response ORDER BY created DESC LIMIT 5;" 2>&1
echo "=== bulk insert test (simulating a different client) ==="
BULK_EMAIL="bulk-$(date +%s)@example.com"
psql "$SUPABASE_DB_URL" -c "INSERT INTO public.signups (email, plan) VALUES ('${BULK_EMAIL}-1','team'),('${BULK_EMAIL}-2','enterprise');" 2>&1
sleep 8
psql "$SUPABASE_DB_URL" -c "SELECT payload->>'email' AS email, payload->>'plan' AS plan FROM public.webhook_receipts WHERE payload->>'email' LIKE '${BULK_EMAIL}%' ORDER BY email;" 2>&1
psql "$SUPABASE_DB_URL" -c "SELECT status_code FROM net._http_response ORDER BY created DESC LIMIT 2;" 2>&1=== last pg_net responses (status) ===
id | status_code | error_msg
----+-------------+-----------
1 | 200 |
(1 row)
=== bulk insert test (simulating a different client) ===
INSERT 0 2
email | plan
-------------------------------+------------
bulk-1785035428@example.com-1 | team
bulk-1785035428@example.com-2 | enterprise
(2 rows)
status_code
-------------
200
200
(2 rows)
10 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