Provision a hardened SELECT-only Postgres role so AI agents can safely read a production database. Works on Supabase and any Postgres. Use when the user wants agents to query prod data, says "read-only role", "safe prod DB access for agents", or is tired of running SQL by hand for agents. Differentiator: this skill CREATES the role and wiring; day-to-day querying belongs in a project-local skill.
76
95%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No known issues
Battle-tested pattern (DeepAPI ADR 0093). A SELECT-only role kills catastrophic writes at the permission level. Residual risks (data leaks, heavy queries) are handled by a denylist and timeouts. Agents stop being blind on prod; the human stops being the SQL bottleneck.
public (via default privileges), then revoke the crown jewels (API keys, webhook payloads, secrets). Never grant the auth schema. Future tables are auto-readable by design; new sensitive tables need a manual revoke.default_transaction_read_only = on plus statement_timeout = '10s'.RLS trap: if prod tables have Row Level Security and no policy mentions the new role, every SELECT returns 0 rows. Fix with alter role ... bypassrls — safe, because bypass only skips row filtering; the SELECT-only grants and denylist still apply.
select rolname from pg_roles where rolname = 'agents_readonly'; — if it exists, you are updating, not creating.docs/database/create-agents-readonly-role.sql) with comments: what / why / how to apply / how to verify / how to revert. Never hand SQL only in chat.~/.zshrc (never committed), e.g. MYPROJ_READONLY_DB_URL. Supabase session pooler: username is agents_readonly.<project-ref>, port 5432. psql comes from Homebrew libpq if missing.-- 1. role + soft guardrails
create role agents_readonly with login password 'REPLACE_ME';
alter role agents_readonly set default_transaction_read_only = on;
alter role agents_readonly set statement_timeout = '10s';
-- 2. the real wall: SELECT-only grants, denylist model
grant usage on schema public to agents_readonly;
grant select on all tables in schema public to agents_readonly;
alter default privileges for role postgres in schema public
grant select on tables to agents_readonly; -- future tables auto-readable
-- 3. denylist: crown jewels stay invisible (adjust per project)
revoke select on table public.api_keys from agents_readonly;
revoke select on table public.email_webhook_events from agents_readonly;
-- 4. only if RLS is enabled and no policy covers this role
alter role agents_readonly bypassrls;Revert: drop owned by agents_readonly; drop role agents_readonly;
URL="$MYPROJ_READONLY_DB_URL"
psql "$URL" -X -c "select current_user;" # -> agents_readonly
psql "$URL" -X -c "show statement_timeout;" # -> 10s
psql "$URL" -X -c "select count(*) from public.<big_table>;" # -> real number, NOT 0
psql "$URL" -X -c "delete from public.<any_table> where false;"
# -> ERROR: read-only transaction (soft guardrail)
psql "$URL" -X -c "begin; set transaction read write; delete from public.<any_table> where false; rollback;"
# -> ERROR: permission denied (the hard wall)
psql "$URL" -X -c "select * from public.<denylisted> limit 1;" # -> ERROR: permission denied
psql "$URL" -X -c "select * from auth.users limit 1;" # -> ERROR: permission deniedWrites must be blocked twice over: once by the read-only guardrail, and again by permission denied with the guardrail off. If any check fails, fix the grants and re-run ALL checks.
bypassrls (step 4 of template).agents_readonly.<project-ref>, not bare agents_readonly.statement timeout on legit queries → query too heavy; add filters/limits. Do not raise the timeout as a first resort.revoke select next to the denylist block.alter role agents_readonly with password '...' then update the env var in ~/.zshrc.66860fb
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.