Agent-skills read-only-postgres
Execute read-only SQL queries against PostgreSQL databases. Use when: (1) querying PostgreSQL data, (2) exploring schemas/tables, (3) running SELECT queries for analysis, (4) checking database contents. Supports multiple database connections with descriptions for auto-selection. Blocks all write operations (INSERT, UPDATE, DELETE, DROP, etc.) for safety.
install
source · Clone the upstream repo
git clone https://github.com/jawwadfirdousi/agent-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jawwadfirdousi/agent-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/read-only-postgres" ~/.claude/skills/jawwadfirdousi-agent-skills-read-only-postgres && rm -rf "$T"
manifest:
skills/read-only-postgres/SKILL.mdsource content
PostgreSQL Read-Only Query Skill
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/read-only-postgres-connections.json.
Security: Set file permissions to
600 since it contains credentials:
chmod 600 connections.json
{ "databases": [ { "name": "app-db-dev", "description": "Primary app database (public schema: users, organizations, orders, order_items, events)", "host": "localhost", "port": 5432, "database": "app_dev", "user": "app_user", "password": "app_password", "sslmode": "disable" }, { "name": "app-db-staging", "description": "Staging database (same schema as primary app)", "host": "localhost", "port": 5432, "database": "app_staging", "user": "app_user", "password": "app_password", "sslmode": "disable" } ] }
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 |
| pii_masking | No | Object mapping table names to arrays of column names to mask |
PII Masking
Mask sensitive data in query results by adding a
pii_masking field to any database config. Middle characters are replaced with *, keeping only the first and last characters visible.
{ "name": "app-db-dev", "host": "localhost", "database": "app_dev", "user": "readonly", "password": "secret", "pii_masking": { "users": ["email", "phone", "first_name", "last_name"], "orders": ["shipping_address"] } }
How it works:
→john@email.comj************m
→555-12345******4
→Jo
(2 chars or fewer are not masked)Jo
Masking is applied automatically when querying a matching table. A footer note indicates which columns were masked.
Usage
List configured databases
python3 scripts/query.py --list
Query a database
python3 scripts/query.py --db app-db-dev --query "SELECT id, email, created_at FROM users LIMIT 10"
List tables
python3 scripts/query.py --db app-db-dev --tables
Show schema
python3 scripts/query.py --db app-db-dev --schema
Limit results
python3 scripts/query.py --db app-db-dev --query "SELECT id, status, total_amount FROM orders" --limit 100
Database Selection
Match user intent to database
description:
| User asks about | Look for description containing |
|---|---|
| users, accounts | users, accounts |
| organizations, teams | organizations, teams |
| orders, payments | orders, payments |
| events, audit logs | events, audit, logs |
| analytics or reporting | analytics, reporting |
| background jobs or queues | jobs, queue, outbox |
If unclear, run
--list and ask user which database.
Safety Features
- Read-only session: Connection uses PostgreSQL
mode (primary protection)readonly=True - Query validation: Only SELECT, SHOW, EXPLAIN, WITH queries allowed (comments/literals stripped; DDL/DML keywords, data-modifying CTEs, SELECT INTO, and sequence mutation functions blocked)
- 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
- PII masking: Configurable per-table column masking to protect sensitive data in query output
Troubleshooting
| Error | Solution |
|---|---|
| Config not found | Create in skill directory |
| Authentication failed | Check username/password in config |
| Connection timeout | Verify host/port, check firewall/VPN |
| SSL error | Try for local databases |
| Permission warning | Run |
Exit Codes
- 0: Success
- 1: Error (config missing, auth failed, invalid query, database error)
Workflow
- Run
to show available databases--list - Match user intent to database description
- Run
or--tables
to explore structure--schema - Execute query with appropriate LIMIT