Supabase / PostgREST
Works with any PostgREST-based API. appctl reads the OpenAPI document PostgREST serves and generates REST tools for each table.
Prerequisites
Section titled “Prerequisites”- A Supabase project URL (like
https://xyz.supabase.co) and the anon key, or a local PostgREST instance. appctlinstalled.
Against a hosted Supabase project
Section titled “Against a hosted Supabase project”export SUPABASE_ANON_KEY='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
appctl sync --supabase https://YOUR-PROJECT.supabase.co \ --anon-key "$SUPABASE_ANON_KEY" \ --forceThe sync probes /rest/v1 first (the Supabase layout). If that 404s, it falls back to the root URL (bare PostgREST). One flag works for either deployment.
The local demo in this repo
Section titled “The local demo in this repo”examples/demos/supabase/ runs a bare PostgREST on top of Postgres with two tables (items, notes). It does not use Supabase’s auth gateway, but the API shape is identical.
1. Start it
Section titled “1. Start it”Docker is required.
cd examples/demos/supabasedocker compose up -d
sleep 10curl -s http://localhost:3010/ | head -c 80Real output:
{"swagger":"2.0","info":{"description":"","title":"standard public schema"...2. Sync
Section titled “2. Sync”appctl sync --supabase http://localhost:3010 --forceReal output:
Synced Supabase: 3 resources, 9 tools written to .appctlGenerated tools:
items: list_items GET /items, create_items POST /items, update_items PATCH /items, delete_items DELETE /itemsnotes: same four tools under /notes3. Confirm they actually work
Section titled “3. Confirm they actually work”SUPABASE_ANON_KEY=anon appctl doctorExpected:
tool method path HTTP verdictlist_items GET /items 200 reachablecreate_items POST /items 200 reachableupdate_items PATCH /items 200 reachabledelete_items DELETE /items 200 reachablelist_notes GET /notes 200 reachablecreate_notes POST /notes 200 reachable...4. Stop
Section titled “4. Stop”docker compose down -vWhat appctl reads
Section titled “What appctl reads”- PostgREST serves its schema as OpenAPI 2 (Swagger) at
/on a bare install, or/rest/v1behind Supabase.appctlprobes both and picks whichever returns a valid document. - It sets the
apikeyheader fromSUPABASE_ANON_KEYon every generated tool.
PostgREST quirks
Section titled “PostgREST quirks”- There is no
get_{table}tool (GET by id). PostgREST uses row filters (?id=eq.1) instead of path segments. The agent can calllist_itemswith a query filter to get one row. - PostgREST exposes its own OpenAPI endpoint at
GET /. This becomes a tool calledlist_introspectionin the schema. Harmless; you can ignore it. - Row-level security is enforced by Postgres. Generated tools might sync without error but return empty results or a 401 at call time. That is RLS working correctly; it is not a bug in
appctl.