Skill

Query PostgreSQL databases with read-only safety guarantees

Executes safe, read-only PostgreSQL queries across multiple configured connections with layered write protection.

Works with postgresqlpostgres

91
Spark score
out of 100
Updated 16 days ago
Version 1.2.0

Add to Favorites

Why it matters

Execute SELECT queries against PostgreSQL databases with defense-in-depth read-only protections that prevent accidental writes, deletes, or schema changes while exploring data across multiple configured connections.

Outcomes

What it gets done

01

List and explore tables, schemas, and database structure across configured connections

02

Execute validated SELECT queries with automatic row and column limits to prevent memory issues

03

Match user intent to the right database using natural-language descriptions

04

Enforce read-only mode through connection settings, query validation, and statement filtering

Install

Add it to your toolbox

Run in your project directory:

curl -fsSL https://spark.entire.vc/get/ag-postgres-readonly-queries | bash

Overview

PostgreSQL Read-Only Query Skill

Executes safe, read-only PostgreSQL queries via scripts/query.py, layering a readonly session, SELECT-only validation, a 30-second timeout, and a 10,000-row cap on top of a connections.json config. Use it when PostgreSQL access must stay strictly read-only. It is not a substitute for a genuinely read-only database role, backups, or production change controls.

What it does

Executes safe, read-only queries against configured PostgreSQL databases, exploring schemas, tables, and data across multiple configured connections with defense-in-depth protection against accidental INSERT/UPDATE/DELETE or DDL.

When to use - and when NOT to

Reach for it any time a query needs to run against a real database but the person or agent running it shouldn't be able to change anything, intentionally or not. Its own protections are explicitly secondary, not primary: they reduce accidental writes but cannot override database-server policy, triggers, extensions, or an over-privileged account, so a database role with genuinely read-only permissions still has to be the real control. Query results can contain personal, confidential, or regulated data - confirm the intended database and avoid exporting or sharing results without explicit authorization. The script is not a replacement for backups, auditing, access reviews, or production change controls.

Inputs and outputs

Requires Python 3.8+ and psycopg2-binary (pip install -r requirements.txt). Setup creates a connections.json file in the skill directory or ~/.config/claude/postgres-connections.json, permissioned to 600 since it holds credentials:

chmod 600 connections.json

with database entries shaped like:

{
  "databases": [
    {
      "name": "production",
      "description": "Main app database - users, orders, transactions",
      "host": "db.example.com",
      "port": 5432,
      "database": "app_prod",
      "user": "readonly_user",
      "password": "your-password",
      "sslmode": "require"
    }
  ]
}

Required fields are name, description, host, database, user, and password; port defaults to 5432 and sslmode defaults to prefer (options: disable, allow, prefer, require, verify-ca, verify-full). Usage runs through scripts/query.py: --list shows configured databases, --db <name> --query "<SQL>" runs a query, --db <name> --tables lists tables, --db <name> --schema shows the schema, and --limit <n> caps result rows. Exit codes are 0 for success and 1 for any error (missing config, failed auth, invalid query, database error).

Integrations

Database selection matches user intent to each connection's description field - questions about users or accounts look for descriptions mentioning users/accounts/customers, orders or sales look for orders/transactions/sales, analytics or metrics look for analytics/metrics/reports, and logs or events look for logs/events/audit; if it's unclear, run --list and ask the user which database to use. Layered safety features: the connection itself runs in PostgreSQL readonly=True mode as the primary protection, query validation only allows SELECT/SHOW/EXPLAIN/WITH statements, multiple statements per query are rejected, SSL mode is configurable for encrypted connections, a 30-second statement timeout is enforced, results are capped at 10,000 rows to prevent out-of-memory errors, columns are capped at 100 characters for readable output, and error messages are sanitized so they never leak passwords. Common troubleshooting: a missing config means creating connections.json in the skill directory; authentication failures mean checking the username/password; connection timeouts mean verifying host/port and firewall/VPN; SSL errors on a local database can be worked around with "sslmode": "disable"; and a permission warning means running chmod 600 connections.json again. The intended workflow: run --list to see available databases, match user intent to a database description, run --tables or --schema to explore structure, then execute the query with an appropriate --limit.

Who it's for

Someone juggling several databases on file at once, where naming the right one by hand every time would get tedious - the description field on each connection entry does that matching automatically, and error messages are scrubbed of credentials before they ever reach the screen.

Source README

PostgreSQL Read-Only Query Skill

When to Use

  • Use when querying PostgreSQL databases and access must stay strictly read-only
  • Use when exploring schemas, tables, and data across multiple configured connections
  • Use when you want defense-in-depth protection against accidental INSERT/UPDATE/DELETE or DDL

Execute safe, read-only queries against configured PostgreSQL databases.

Requirements

  • Python 3.8+
  • psycopg2-binary: pip install -r requirements.txt

Setup

Create connections.json in the skill directory or ~/.config/claude/postgres-connections.json.

Security: Set file permissions to 600 since it contains credentials:

chmod 600 connections.json
{
  "databases": [
    {
      "name": "production",
      "description": "Main app database - users, orders, transactions",
      "host": "db.example.com",
      "port": 5432,
      "database": "app_prod",
      "user": "readonly_user",
      "password": "your-password",
      "sslmode": "require"
    }
  ]
}

Config Fields

Field Required Description
name Yes Identifier for the database (case-insensitive)
description Yes What data this database contains (used for auto-selection)
host Yes Database hostname
port No Port number (default: 5432)
database Yes Database name
user Yes Username
password Yes Password
sslmode No SSL mode: disable, allow, prefer (default), require, verify-ca, verify-full

Usage

List configured databases

python3 scripts/query.py --list

Query a database

python3 scripts/query.py --db production --query "SELECT * FROM users LIMIT 10"

List tables

python3 scripts/query.py --db production --tables

Show schema

python3 scripts/query.py --db production --schema

Limit results

python3 scripts/query.py --db production --query "SELECT * FROM orders" --limit 100

Database Selection

Match user intent to database description:

User asks about Look for description containing
users, accounts users, accounts, customers
orders, sales orders, transactions, sales
analytics, metrics analytics, metrics, reports
logs, events logs, events, audit

If unclear, run --list and ask user which database.

Safety Features

  • Read-only session: Connection uses PostgreSQL readonly=True mode (primary protection)
  • Query validation: Only SELECT, SHOW, EXPLAIN, WITH queries allowed
  • Single statement: Multiple statements per query rejected
  • SSL support: Configurable SSL mode for encrypted connections
  • Query timeout: 30-second statement timeout enforced
  • Memory protection: Max 10,000 rows per query to prevent OOM
  • Column width cap: 100 char max per column for readable output
  • Credential sanitization: Error messages don't leak passwords

Troubleshooting

Error Solution
Config not found Create connections.json in skill directory
Authentication failed Check username/password in config
Connection timeout Verify host/port, check firewall/VPN
SSL error Try "sslmode": "disable" for local databases
Permission warning Run chmod 600 connections.json

Exit Codes

  • 0: Success
  • 1: Error (config missing, auth failed, invalid query, database error)

Workflow

  1. Run --list to show available databases
  2. Match user intent to database description
  3. Run --tables or --schema to explore structure
  4. Execute query with appropriate LIMIT

Limitations

  • Read-only protections reduce accidental writes but cannot override database-server policy,
    triggers, extensions, or an over-privileged account. Use a database role with read-only
    permissions as the primary control.
  • Query results can contain personal, confidential, or regulated data. Confirm the intended
    database and avoid exporting or sharing results without explicit authorization.
  • The script is not a replacement for backups, auditing, access reviews, or production change
    controls.

Discussion

Questions & comments · 0

Sign In Sign in to leave a comment.