{"id":"bd3c2529-c63e-4b5e-beba-b1901cf140df","shortId":"tZNGGf","kind":"skill","title":"postgres","tagline":"Use when writing PostgreSQL SQL, editing .sql files, psql commands, postgresql.conf, psycopg or asyncpg code, indexes, JSONB, PL/pgSQL, extensions, roles, RLS, replication, migrations, or query tuning.","description":"# PostgreSQL\n\nPostgreSQL is an advanced open-source relational database with extensive support for SQL standards, JSONB, full-text search, PL/pgSQL, and extensibility.\n\n## Quick Reference\n\n### Connection Patterns\n\n```bash\n# URI format\n\"postgresql://app:secret@localhost:5432/mydb?sslmode=require&application_name=myapp\"\n\n# Multiple hosts (failover)\n\"postgresql://app:secret@primary:5432,standby:5432/mydb?target_session_attrs=read-write\"\n```\n\n```python\n# asyncpg (async)\npool = await asyncpg.create_pool(\"postgresql://app:secret@localhost/mydb\", min_size=5, max_size=20)\nasync with pool.acquire() as conn:\n    rows = await conn.fetch(\"SELECT id, name FROM users WHERE status = $1\", \"active\")\n\n# psycopg v3 (async)\nasync with await psycopg.AsyncConnection.connect(conninfo) as conn:\n    async with conn.cursor() as cur:\n        await cur.execute(\"SELECT id, name FROM users WHERE id = %s\", (42,))\n```\n\n### Indexing Essentials\n\n| Type | Best For | Example |\n|------|----------|---------|\n| B-tree (default) | Equality, range on scalars | `CREATE INDEX idx ON orders (created_at DESC)` |\n| GIN | JSONB, arrays, full-text, trigram | `CREATE INDEX idx ON docs USING gin (data)` |\n| GiST | Geometry, range types, nearest-neighbor | `CREATE INDEX idx ON events USING gist (during)` |\n| BRIN | Large, naturally ordered (time-series) | `CREATE INDEX idx ON logs USING brin (ts)` |\n\n**Partial indexes** -- index only the rows that matter:\n\n```sql\nCREATE INDEX idx_orders_active ON orders (user_id)\n WHERE status IN ('pending', 'processing');\n```\n\n### Key JSONB Patterns\n\n```sql\n-- Navigation\nSELECT data->>'name' FROM docs;             -- text extraction\nSELECT data @> '{\"status\": \"active\"}' FROM docs;  -- containment\n\n-- GIN index for containment\nCREATE INDEX idx_docs_data ON docs USING gin (data jsonb_path_ops);\n\n-- Build objects\nSELECT jsonb_build_object('id', u.id, 'name', u.name) FROM users u;\n```\n\n### EXPLAIN Usage\n\n```sql\n-- Full diagnostic\nEXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) SELECT ...;\n\n-- Safe for mutating queries (no execution)\nEXPLAIN (COSTS, VERBOSE) DELETE FROM orders WHERE created_at < '2020-01-01';\n```\n\n| Symptom | Likely Cause | Fix |\n|---------|-------------|-----|\n| `Seq Scan` on large table | Missing/unused index | Create index, check predicate |\n| `Sort Method: external merge Disk` | `work_mem` too low | Increase `work_mem` |\n| High `Rows Removed by Filter` | Index not selective | Refine index, add partial index |\n\n<workflow>\n\n## Workflow\n\n### Step 1: Schema Design\n\nDefine tables with appropriate types. Use JSONB for semi-structured data, arrays for small sets, and normalized tables for relational data. Always define primary keys.\n\n### Step 2: Write Queries\n\nUse parameterized queries (`$1` for asyncpg, `%s` for psycopg). Use CTEs for readability. Prefer `EXISTS` over `IN` for correlated subqueries.\n\n### Step 3: Index Strategy\n\nStart with B-tree indexes on WHERE/JOIN/ORDER BY columns. Use partial indexes to limit index size. Add GIN indexes for JSONB containment queries. Prefer expression indexes for computed predicates.\n\n### Step 4: Performance Tuning\n\nRun `EXPLAIN (ANALYZE, BUFFERS)` on slow queries. Check `pg_stat_statements` for top queries by total time. Tune `shared_buffers`, `work_mem`, and autovacuum settings.\n\n### Step 5: Validate\n\nConfirm EXPLAIN plans use indexes. Check `pg_stat_user_tables` for sequential scan counts on large tables. Verify connection pooling (pgbouncer) is configured for production.\n\n</workflow>\n\n<guardrails>\n\n## Guardrails\n\n- **Always use parameterized queries** -- never interpolate user input. Use `$1` placeholders (asyncpg) or `%s` (psycopg).\n- **Prefer partial indexes** -- indexing only relevant rows reduces size and improves write performance.\n- **EXPLAIN before optimizing** -- always measure before adding indexes or rewriting queries. Use `EXPLAIN (ANALYZE, BUFFERS)` for real execution stats.\n- **Use JSONB, not JSON** -- JSONB is decomposed binary, supports GIN indexing and operators. Plain JSON is only for exact text preservation.\n- **Connection pooling in production** -- use pgbouncer or built-in pool. Never open unbounded connections from application servers.\n- **pg_stat_statements for production monitoring** -- identifies top queries by time, calls, and cache hit ratio.\n- **Avoid `SELECT *`** -- name columns to enable covering indexes and prevent schema-change breakage.\n\n</guardrails>\n\n<validation>\n\n### Validation Checkpoint\n\nBefore delivering PostgreSQL code, verify:\n\n- [ ] All queries use parameterized placeholders (no string interpolation)\n- [ ] EXPLAIN output confirms index usage for critical queries\n- [ ] Partial indexes are used where only a subset of rows is queried\n- [ ] JSONB columns use GIN indexes for containment queries\n- [ ] Connection pooling is addressed (pgbouncer or pool parameter)\n- [ ] sslmode is set to at least `require` for non-local connections\n\n</validation>\n\n<example>\n\n## Example\n\n**Task:** EXPLAIN ANALYZE and index optimization for a slow orders query.\n\n```sql\n-- Step 1: Check current plan\nEXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)\nSELECT o.id, o.total, o.created_at, u.name\n  FROM orders o\n  JOIN users u ON u.id = o.user_id\n WHERE o.status = 'pending'\n   AND o.created_at > NOW() - INTERVAL '7 days'\n ORDER BY o.created_at DESC\n LIMIT 50;\n\n-- Step 2: If Seq Scan on orders, add a partial composite index\nCREATE INDEX CONCURRENTLY idx_orders_pending_recent\n    ON orders (created_at DESC)\n WHERE status = 'pending';\n\n-- Step 3: Re-run EXPLAIN to confirm Index Scan\nEXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)\nSELECT o.id, o.total, o.created_at, u.name\n  FROM orders o\n  JOIN users u ON u.id = o.user_id\n WHERE o.status = 'pending'\n   AND o.created_at > NOW() - INTERVAL '7 days'\n ORDER BY o.created_at DESC\n LIMIT 50;\n\n-- Step 4: Check pg_stat_statements for overall impact\nSELECT calls, round(mean_exec_time::numeric, 1) AS mean_ms, query\n  FROM pg_stat_statements\n ORDER BY total_exec_time DESC\n LIMIT 10;\n```\n\n</example>\n\n---\n\n## Monitoring Strategy\n\n### pg_stat_statements Setup\n\nEnable in `postgresql.conf` (requires restart):\n\n```ini\nshared_preload_libraries = 'pg_stat_statements'\npg_stat_statements.track = all\npg_stat_statements.max = 10000\n```\n\n```sql\nCREATE EXTENSION IF NOT EXISTS pg_stat_statements;\n```\n\n### Key pg_stat_statements Queries\n\n```sql\n-- Top queries by total execution time\nSELECT\n    round(total_exec_time::numeric, 1) AS total_ms,\n    calls,\n    round(mean_exec_time::numeric, 1)  AS mean_ms,\n    round(stddev_exec_time::numeric, 1) AS stddev_ms,\n    round((100 * total_exec_time / sum(total_exec_time) OVER ())::numeric, 1) AS pct,\n    left(query, 120) AS query\nFROM pg_stat_statements\nORDER BY total_exec_time DESC\nLIMIT 20;\n\n-- Top queries by average latency (outliers)\nSELECT\n    calls,\n    round(mean_exec_time::numeric, 2) AS mean_ms,\n    left(query, 120) AS query\nFROM pg_stat_statements\nWHERE calls > 100\nORDER BY mean_exec_time DESC\nLIMIT 20;\n\n-- Cache hit ratio per query\nSELECT\n    calls,\n    round(100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0), 1) AS cache_hit_pct,\n    left(query, 120) AS query\nFROM pg_stat_statements\nORDER BY shared_blks_read DESC\nLIMIT 20;\n\n-- Reset stats\nSELECT pg_stat_statements_reset();\n```\n\n### Sequential Scan Detection (pg_stat_user_tables)\n\n```sql\n-- Tables with high sequential scan counts\nSELECT\n    schemaname,\n    relname AS table_name,\n    seq_scan,\n    seq_tup_read,\n    idx_scan,\n    round(100.0 * seq_scan / nullif(seq_scan + idx_scan, 0), 1) AS seq_pct,\n    n_live_tup\nFROM pg_stat_user_tables\nWHERE seq_scan > 0\n  AND n_live_tup > 10000\nORDER BY seq_scan DESC\nLIMIT 20;\n```\n\n### Bloat Detection\n\n```sql\n-- Table bloat estimate\nSELECT\n    schemaname,\n    tablename,\n    pg_size_pretty(pg_total_relation_size(schemaname || '.' || tablename)) AS total_size,\n    n_dead_tup,\n    n_live_tup,\n    round(100.0 * n_dead_tup / nullif(n_live_tup + n_dead_tup, 0), 1) AS dead_pct,\n    last_autovacuum,\n    last_autoanalyze\nFROM pg_stat_user_tables\nWHERE n_dead_tup > 1000\nORDER BY n_dead_tup DESC\nLIMIT 20;\n\n-- Index bloat (using pg_relation_size vs estimated used)\nSELECT\n    indexrelname,\n    pg_size_pretty(pg_relation_size(indexrelid)) AS index_size,\n    idx_scan,\n    idx_tup_read,\n    idx_tup_fetch\nFROM pg_stat_user_indexes\nORDER BY pg_relation_size(indexrelid) DESC\nLIMIT 20;\n```\n\n### Active Query Monitoring (pg_stat_activity)\n\n```sql\n-- Long-running queries\nSELECT\n    pid,\n    now() - query_start AS duration,\n    state,\n    wait_event_type,\n    wait_event,\n    left(query, 100) AS query\nFROM pg_stat_activity\nWHERE state != 'idle'\n  AND query_start < now() - INTERVAL '30 seconds'\nORDER BY duration DESC;\n\n-- Blocking and blocked queries\nSELECT\n    blocked.pid          AS blocked_pid,\n    blocking.pid         AS blocking_pid,\n    left(blocked.query, 80)  AS blocked_query,\n    left(blocking.query, 80) AS blocking_query\nFROM pg_stat_activity blocked\nJOIN pg_stat_activity blocking\n  ON blocking.pid = ANY(pg_blocking_pids(blocked.pid))\nWHERE cardinality(pg_blocking_pids(blocked.pid)) > 0;\n\n-- Terminate a specific pid (superuser only)\nSELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE pid = <target_pid>;\n```\n\n---\n\n## Autovacuum Tuning\n\n### Per-Table Settings\n\nOverride global autovacuum settings for high-churn tables:\n\n```sql\n-- High-churn table: trigger vacuum more aggressively\nALTER TABLE orders SET (\n    autovacuum_vacuum_scale_factor     = 0.01,   -- 1% dead tuples (default 20%)\n    autovacuum_analyze_scale_factor    = 0.005,  -- 0.5% changed for analyze\n    autovacuum_vacuum_cost_delay       = 2,      -- ms; lower = faster vacuum\n    autovacuum_vacuum_threshold        = 50,     -- minimum dead tuples before trigger\n    autovacuum_analyze_threshold       = 50\n);\n\n-- Large append-only table: raise threshold to reduce noise\nALTER TABLE events SET (\n    autovacuum_vacuum_scale_factor  = 0.001,\n    autovacuum_analyze_scale_factor = 0.001\n);\n```\n\n### Dead Tuple Threshold Formula\n\nAutovacuum triggers when:\n\n```text\ndead_tuples > autovacuum_vacuum_threshold + autovacuum_vacuum_scale_factor * n_live_tup\n```\n\nFor a 10M-row table at the default `scale_factor=0.20`:\n\n- Threshold = 50 + 0.20 × 10,000,000 = **2,000,050 dead tuples** before vacuum runs.\n- Reduce `scale_factor` to `0.01` for tables with frequent UPDATE/DELETE.\n\n### Global postgresql.conf Tuning\n\n```ini\n# Reduce I/O impact of autovacuum\nautovacuum_vacuum_cost_delay = 2ms          # default 2ms (pg14+); was 20ms\nautovacuum_vacuum_cost_limit = 400          # default 200; allows faster passes\n\n# Scale factor defaults (override per-table for hot tables)\nautovacuum_vacuum_scale_factor  = 0.05     # default 0.20\nautovacuum_analyze_scale_factor = 0.02     # default 0.10\n\n# Worker count\nautovacuum_max_workers = 5                  # default 3\n```\n\n---\n\n## Connection Pooling\n\n### PgBouncer vs pgpool-II\n\n| Feature | PgBouncer | pgpool-II |\n|---------|-----------|-----------|\n| Primary purpose | Connection pooling | Pooling + load balancing + HA |\n| Modes | Session, Transaction, Statement | Session, Transaction |\n| Overhead | Very low (C, single process) | Higher (more features) |\n| Read scaling | No built-in | Routes SELECTs to replicas |\n| HA / failover | No (use external) | Yes (watchdog, VIP) |\n| Complexity | Simple config | More complex |\n| Typical use | Application → single primary | Need query routing or HA middleware |\n\n### PgBouncer Configuration (pgbouncer.ini)\n\n```ini\n[databases]\nmydb = host=127.0.0.1 port=5432 dbname=mydb\n\n[pgbouncer]\nlisten_port        = 6432\nlisten_addr        = 0.0.0.0\nauth_type          = scram-sha-256\nauth_file          = /etc/pgbouncer/userlist.txt\npool_mode          = transaction        ; transaction mode = best performance\nmax_client_conn    = 1000\ndefault_pool_size  = 25\nmin_pool_size      = 5\nreserve_pool_size  = 5\nreserve_pool_timeout = 3\nserver_idle_timeout = 600\nlog_connections    = 0\nlog_disconnections = 0\n```\n\n### Transaction vs Session Mode\n\n| Mode | Behaviour | Use Case |\n|------|-----------|----------|\n| **Transaction** | Server connection held only during transaction | Stateless apps; highest concurrency |\n| **Session** | Server connection held for full client session | Requires session state (temp tables, prepared statements) |\n| **Statement** | Released after each statement | Rarely used; autocommit only |\n\n**Transaction mode caveat:** prepared statements and advisory locks are incompatible with transaction mode. Disable `prepared_statements` at the driver level or use `DEALLOCATE ALL` at transaction end.\n\n---\n\n## Cross-References\n\n- **Gemini PostgreSQL extension**: `gemini extensions install https://github.com/gemini-cli-extensions/postgresql` — 24 tools for query execution, schema inspection, EXPLAIN analysis, and more.\n\n---\n\n## References Index\n\nFor detailed guides and code examples, refer to the following documents in `references/`:\n\n- **[Advanced SQL Patterns](references/queries.md)** -- CTEs, window functions, JSONB operations, array ops, lateral joins, recursive queries.\n- **[Indexing & Performance](references/indexing.md)** -- Index types (B-tree, GIN, GiST, BRIN), partial indexes, expression indexes.\n- **[Administration](references/admin.md)** -- Configuration, roles, connection pooling (pgbouncer), vacuuming, WAL.\n- **[psql CLI](references/psql.md)** -- psql commands, \\d meta-commands, .psqlrc customization.\n- **[PL/pgSQL Development](references/plpgsql.md)** -- Functions, procedures, triggers, exception handling, DO blocks.\n- **[Performance Tuning](references/performance.md)** -- EXPLAIN, pg_stat_statements, autovacuum, parallel query.\n- **[Connection Patterns](references/connections.md)** -- psycopg v3, asyncpg, SQLAlchemy, node-postgres, Rust sqlx.\n- **[JSON/JSONB Patterns](references/json.md)** -- JSONB operators, SQL/JSON path, GIN indexing, generated columns.\n- **[Security](references/security.md)** -- Role management, RLS, column privileges, SSL/TLS, pgAudit.\n- **[Key Extensions](references/extensions.md)** -- PostGIS, pgvector, pg_cron, pg_stat_statements, pg_trgm, TimescaleDB.\n- **[Replication & HA](references/replication.md)** -- Streaming replication, logical replication, Patroni, PITR.\n- **[Schema Migrations & DevOps](references/migrations.md)** -- Alembic, Flyway, zero-downtime migrations, pgTAP testing.\n\n---\n\n## Official References\n\n- <https://www.postgresql.org/docs/current/>\n- <https://wiki.postgresql.org/>\n\n## Shared Styleguide Baseline\n\n- Use shared styleguides for generic language/framework rules to reduce duplication in this skill.\n- [General Principles](https://github.com/cofin/flow/blob/main/templates/styleguides/general.md)\n- [PostgreSQL](https://github.com/cofin/flow/blob/main/templates/styleguides/databases/postgres_psql.md)\n- Keep this skill focused on tool-specific workflows, edge cases, and integration details.","tags":["postgres","flow","cofin","agent-skills","ai-agents","beads","claude-code","codex","cursor","developer-tools","gemini-cli","opencode"],"capabilities":["skill","source-cofin","skill-postgres","topic-agent-skills","topic-ai-agents","topic-beads","topic-claude-code","topic-codex","topic-cursor","topic-developer-tools","topic-gemini-cli","topic-opencode","topic-plugin","topic-slash-commands","topic-spec-driven-development"],"categories":["flow"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/cofin/flow/postgres","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add cofin/flow","source_repo":"https://github.com/cofin/flow","install_from":"skills.sh"}},"qualityScore":"0.455","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 11 github stars · SKILL.md body (14,809 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:07:38.609Z","embedding":null,"createdAt":"2026-04-23T13:04:00.712Z","updatedAt":"2026-05-18T19:07:38.609Z","lastSeenAt":"2026-05-18T19:07:38.609Z","tsv":"'-01':308,309 '/cofin/flow/blob/main/templates/styleguides/databases/postgres_psql.md)':1934 '/cofin/flow/blob/main/templates/styleguides/general.md)':1930 '/docs/current/':1908 '/etc/pgbouncer/userlist.txt':1622 '/gemini-cli-extensions/postgresql':1741 '0':999,1065,1081,1133,1298,1656,1659 '0.0.0.0':1613 '0.001':1403,1408 '0.005':1358 '0.01':1348,1459 '0.02':1515 '0.05':1508 '0.10':1517 '0.20':1440,1443,1510 '0.5':1359 '000':1445,1446,1448 '050':1449 '1':114,352,388,506,690,823,889,899,908,923,1000,1066,1134,1349 '10':839,1444 '100':913,971,1229 '100.0':988,1057,1122 '1000':1151,1633 '10000':861,1086 '10m':1432 '10m-row':1431 '120':928,962,1007 '127.0.0.1':1602 '2':382,733,956,1367,1447 '20':98,942,979,1021,1093,1159,1202,1353 '200':1490 '2020':307 '20ms':1483 '24':1742 '25':1637 '256':1619 '2ms':1478,1480 '3':406,760,1525,1649 '30':1244 '4':440,808 '400':1488 '42':141 '5':95,469,1523,1641,1645 '50':731,806,1375,1384,1442 '5432':74,1604 '5432/mydb':62,76 '600':1653 '6432':1610 '7':723,798 '80':1265,1271 'activ':115,222,247,1203,1208,1235,1278,1283,1313 'ad':531 'add':347,426,739 'addr':1612 'address':659 'administr':1798 'advanc':32,1768 'advisori':1709 'aggress':1339 'alemb':1896 'allow':1491 'alter':1340,1395 'alway':377,497,528 'analysi':1750 'analyz':287,445,538,679,695,770,1355,1362,1382,1405,1512 'app':59,71,90,1676 'append':1387 'append-on':1386 'applic':65,581,1586 'appropri':358 'array':166,367,1777 'async':85,99,118,119,126 'asyncpg':15,84,390,508,1843 'asyncpg.create':88 'attr':79 'auth':1614,1620 'autoanalyz':1141 'autocommit':1701 'autovacuum':466,1139,1316,1324,1344,1354,1363,1372,1381,1399,1404,1413,1419,1422,1473,1474,1484,1504,1511,1520,1835 'averag':946 'avoid':599 'await':87,105,121,131 'b':149,412,1789 'b-tree':148,411,1788 'backend':1308 'balanc':1544 'baselin':1912 'bash':56 'behaviour':1665 'best':145,1628 'binari':551 'blks':990,994,997,1017 'bloat':1094,1098,1161 'block':1250,1252,1257,1261,1267,1273,1279,1284,1289,1295,1827 'blocked.pid':1255,1291,1297 'blocked.query':1264 'blocking.pid':1259,1286 'blocking.query':1270 'breakag':612 'brin':194,207,1793 'buffer':288,446,462,539,696,771 'build':268,272 'built':573,1565 'built-in':572,1564 'c':1555 'cach':596,980,1002 'call':594,817,893,950,970,986 'cardin':1293 'case':1667,1945 'caus':312 'caveat':1705 'chang':611,1360 'check':323,450,476,691,809 'checkpoint':614 'churn':1329,1334 'cli':1808 'client':1631,1685 'code':16,618,1759 'column':418,602,649,1860,1866 'command':11,1811,1815 'complex':1579,1583 'composit':742 'comput':437 'concurr':746,1678 'config':1581 'configur':493,1596,1800 'confirm':471,630,766 'conn':103,125,1632 'conn.cursor':128 'conn.fetch':106 'connect':54,489,565,579,656,675,1526,1540,1655,1670,1681,1802,1838 'conninfo':123 'contain':250,254,431,654 'correl':403 'cost':299,1365,1476,1486 'count':484,1042,1519 'cover':605 'creat':156,161,171,186,201,218,255,305,321,744,753,863 'critic':634 'cron':1876 'cross':1731 'cross-refer':1730 'ctes':395,1772 'cur':130 'cur.execute':132 'current':692 'custom':1817 'd':1812 'data':178,238,245,259,264,366,376 'databas':37,1599 'day':724,799 'dbname':1605 'dead':1116,1124,1131,1136,1149,1155,1350,1377,1409,1417,1450 'dealloc':1725 'decompos':550 'default':151,1352,1437,1479,1489,1496,1509,1516,1524,1634 'defin':355,378 'delay':1366,1477 'delet':301 'deliv':616 'desc':163,729,755,804,837,940,977,1019,1091,1157,1200,1249 'design':354 'detail':1756,1948 'detect':1031,1095 'develop':1819 'devop':1894 'diagnost':285 'disabl':1716 'disconnect':1658 'disk':329 'doc':175,241,249,258,261 'document':1765 'downtim':1900 'driver':1721 'duplic':1922 'durat':1220,1248 'edg':1944 'edit':7 'enabl':604,846 'end':1729 'equal':152 'essenti':143 'estim':1099,1167 'event':190,1223,1226,1397 'exact':562 'exampl':147,676,1760 'except':1824 'exec':820,835,886,896,905,915,919,938,953,975 'execut':297,542,881,1746 'exist':399,867 'explain':281,286,298,444,472,525,537,628,678,694,764,769,1749,1831 'express':434,1796 'extens':20,39,51,864,1735,1737,1871 'extern':327,1575 'extract':243 'factor':1347,1357,1402,1407,1425,1439,1457,1495,1507,1514 'failov':70,1572 'faster':1370,1492 'featur':1533,1560 'fetch':1188 'file':9,1621 'filter':341 'fix':313 'flyway':1897 'focus':1938 'follow':1764 'format':58,289,697,772 'formula':1412 'frequent':1463 'full':46,168,284,1684 'full-text':45,167 'function':1774,1821 'gemini':1733,1736 'general':1926 'generat':1859 'generic':1917 'geometri':180 'gin':164,177,251,263,427,553,651,1791,1857 'gist':179,192,1792 'github.com':1740,1929,1933 'github.com/cofin/flow/blob/main/templates/styleguides/databases/postgres_psql.md)':1932 'github.com/cofin/flow/blob/main/templates/styleguides/general.md)':1928 'github.com/gemini-cli-extensions/postgresql':1739 'global':1323,1465 'guardrail':496 'guid':1757 'ha':1545,1571,1593,1884 'handl':1825 'held':1671,1682 'high':337,1039,1328,1333 'high-churn':1327,1332 'higher':1558 'highest':1677 'hit':597,981,991,995,1003 'host':69,1601 'hot':1502 'i/o':1470 'id':108,134,139,226,274,714,789 'identifi':589 'idl':1238,1651 'idx':158,173,188,203,220,257,747,1054,1063,1181,1183,1186 'ii':1532,1537 'impact':815,1471 'improv':522 'incompat':1712 'increas':334 'index':17,142,157,172,187,202,210,211,219,252,256,320,322,342,346,349,407,414,421,424,428,435,475,514,515,532,554,606,631,637,652,681,743,745,767,1160,1179,1193,1754,1783,1786,1795,1797,1858 'indexrelid':1177,1199 'indexrelnam':1170 'ini':851,1468,1598 'input':504 'inspect':1748 'instal':1738 'integr':1947 'interpol':502,627 'interv':722,797,1243 'join':708,783,1280,1780 'json':547,558 'json/jsonb':1850 'jsonb':18,44,165,233,265,271,361,430,545,548,648,1775,1853 'keep':1935 'key':232,380,871,1870 'language/framework':1918 'larg':195,317,486,1385 'last':1138,1140 'latenc':947 'later':1779 'least':669 'left':926,960,1005,1227,1263,1269 'level':1722 'librari':854 'like':311 'limit':423,730,805,838,941,978,1020,1092,1158,1201,1487 'listen':1608,1611 'live':1071,1084,1119,1128,1427 'load':1543 'local':674 'localhost':61 'localhost/mydb':92 'lock':1710 'log':205,1654,1657 'logic':1888 'long':1211 'long-run':1210 'low':333,1554 'lower':1369 'manag':1864 'matter':216 'max':96,1521,1630 'mean':819,825,895,901,952,958,974 'measur':529 'mem':331,336,464 'merg':328 'meta':1814 'meta-command':1813 'method':326 'middlewar':1594 'migrat':24,1893,1901 'min':93,1638 'minimum':1376 'missing/unused':319 'mode':1546,1624,1627,1663,1664,1704,1715 'monitor':588,840,1205 'ms':826,892,902,911,959,1368 'multipl':68 'mutat':294 'myapp':67 'mydb':1600,1606 'n':1070,1083,1115,1118,1123,1127,1130,1148,1154,1426 'name':66,109,135,239,276,601,1048 'natur':196 'navig':236 'nearest':184 'nearest-neighbor':183 'need':1589 'neighbor':185 'never':501,576 'node':1846 'node-postgr':1845 'nois':1394 'non':673 'non-loc':672 'normal':372 'nullif':992,1060,1126 'numer':822,888,898,907,922,955 'o':707,782 'o.created':702,719,727,777,794,802 'o.id':700,775 'o.status':716,791 'o.total':701,776 'o.user':713,788 'object':269,273 'offici':1904 'op':267,1778 'open':34,577 'open-sourc':33 'oper':556,1776,1854 'optim':527,682 'order':160,197,221,224,303,686,706,725,738,748,752,781,800,832,935,972,1014,1087,1152,1194,1246,1342 'outlier':948 'output':629 'overal':814 'overhead':1552 'overrid':1322,1497 'parallel':1836 'paramet':663 'parameter':386,499,623 'partial':209,348,420,513,636,741,1794 'pass':1493 'path':266,1856 'patroni':1890 'pattern':55,234,1770,1839,1851 'pct':925,1004,1069,1137 'pend':230,717,749,758,792 'per':983,1319,1499 'per-tabl':1318,1498 'perform':441,524,1629,1784,1828 'pg':451,477,583,810,829,842,855,868,872,932,966,1011,1025,1032,1074,1103,1106,1143,1163,1171,1174,1190,1196,1206,1233,1276,1281,1288,1294,1306,1311,1832,1875,1877,1880 'pg14':1481 'pg_stat_statements.max':860 'pg_stat_statements.track':858 'pgaudit':1869 'pgbouncer':491,570,660,1528,1534,1595,1607,1804 'pgbouncer.ini':1597 'pgpool':1531,1536 'pgpool-ii':1530,1535 'pgtap':1902 'pgvector':1874 'pid':1215,1258,1262,1290,1296,1302,1309,1315 'pitr':1891 'pl/pgsql':19,49,1818 'placehold':507,624 'plain':557 'plan':473,693 'pool':86,89,490,566,575,657,662,1527,1541,1542,1623,1635,1639,1643,1647,1803 'pool.acquire':101 'port':1603,1609 'postgi':1873 'postgr':1,1847 'postgresql':5,28,29,617,1734,1931 'postgresql.conf':12,848,1466 'predic':324,438 'prefer':398,433,512 'preload':853 'prepar':1692,1706,1717 'preserv':564 'pretti':1105,1173 'prevent':608 'primari':73,379,1538,1588 'principl':1927 'privileg':1867 'procedur':1822 'process':231,1557 'product':495,568,587 'psql':10,1807,1810 'psqlrc':1816 'psycopg':13,116,393,511,1841 'psycopg.asyncconnection.connect':122 'purpos':1539 'python':83 'queri':26,295,384,387,432,449,456,500,535,591,621,635,647,655,687,827,875,878,927,930,944,961,964,984,1006,1009,1204,1213,1217,1228,1231,1240,1253,1268,1274,1590,1745,1782,1837 'quick':52 'rais':1390 'rang':153,181 'rare':1699 'ratio':598,982 're':762 're-run':761 'read':81,998,1018,1053,1185,1561 'read-writ':80 'readabl':397 'real':541 'recent':750 'recurs':1781 'reduc':519,1393,1455,1469,1921 'refer':53,1732,1753,1761,1767,1905 'references/admin.md':1799 'references/connections.md':1840 'references/extensions.md':1872 'references/indexing.md':1785 'references/json.md':1852 'references/migrations.md':1895 'references/performance.md':1830 'references/plpgsql.md':1820 'references/psql.md':1809 'references/queries.md':1771 'references/replication.md':1885 'references/security.md':1862 'refin':345 'relat':36,375,1108,1164,1175,1197 'releas':1695 'relev':517 'relnam':1045 'remov':339 'replic':23,1883,1887,1889 'replica':1570 'requir':64,670,849,1687 'reserv':1642,1646 'reset':1022,1028 'restart':850 'rewrit':534 'rls':22,1865 'role':21,1801,1863 'round':818,884,894,903,912,951,987,1056,1121 'rout':1567,1591 'row':104,214,338,518,645,1433 'rule':1919 'run':443,763,1212,1454 'rust':1848 'safe':292 'scalar':155 'scale':1346,1356,1401,1406,1424,1438,1456,1494,1506,1513,1562 'scan':315,483,736,768,1030,1041,1050,1055,1059,1062,1064,1080,1090,1182 'schema':353,610,1747,1892 'schema-chang':609 'schemanam':1044,1101,1110 'scram':1617 'scram-sha':1616 'search':48 'second':1245 'secret':60,72,91 'secur':1861 'select':107,133,237,244,270,291,344,600,699,774,816,883,949,985,1024,1043,1100,1169,1214,1254,1305,1568 'semi':364 'semi-structur':363 'seq':314,735,1049,1051,1058,1061,1068,1079,1089 'sequenti':482,1029,1040 'seri':200 'server':582,1650,1669,1680 'session':78,1547,1550,1662,1679,1686,1688 'set':370,467,666,1321,1325,1343,1398 'setup':845 'sha':1618 'share':461,852,989,993,996,1016,1910,1914 'simpl':1580 'singl':1556,1587 'size':94,97,425,520,1104,1109,1114,1165,1172,1176,1180,1198,1636,1640,1644 'skill':1925,1937 'skill-postgres' 'slow':448,685 'small':369 'sort':325 'sourc':35 'source-cofin' 'specif':1301,1942 'sql':6,8,42,217,235,283,688,862,876,1036,1096,1209,1331,1769 'sql/json':1855 'sqlalchemi':1844 'sqlx':1849 'ssl/tls':1868 'sslmode':63,664 'standard':43 'standbi':75 'start':409,1218,1241 'stat':452,478,543,584,811,830,843,856,869,873,933,967,1012,1023,1026,1033,1075,1144,1191,1207,1234,1277,1282,1312,1833,1878 'state':1221,1237,1689 'stateless':1675 'statement':453,585,812,831,844,857,870,874,934,968,1013,1027,1549,1693,1694,1698,1707,1718,1834,1879 'status':113,228,246,757 'stddev':904,910 'step':351,381,405,439,468,689,732,759,807 'strategi':408,841 'stream':1886 'string':626 'structur':365 'styleguid':1911,1915 'subqueri':404 'subset':643 'sum':917 'superus':1303 'support':40,552 'symptom':310 'tabl':318,356,373,480,487,1035,1037,1047,1077,1097,1146,1320,1330,1335,1341,1389,1396,1434,1461,1500,1503,1691 'tablenam':1102,1111 'target':77 'task':677 'temp':1690 'termin':1299,1307 'test':1903 'text':47,169,242,290,563,698,773,1416 'threshold':1374,1383,1391,1411,1421,1441 'time':199,459,593,821,836,882,887,897,906,916,920,939,954,976 'time-seri':198 'timeout':1648,1652 'timescaledb':1882 'tool':1743,1941 'tool-specif':1940 'top':455,590,877,943 'topic-agent-skills' 'topic-ai-agents' 'topic-beads' 'topic-claude-code' 'topic-codex' 'topic-cursor' 'topic-developer-tools' 'topic-gemini-cli' 'topic-opencode' 'topic-plugin' 'topic-slash-commands' 'topic-spec-driven-development' 'total':458,834,880,885,891,914,918,937,1107,1113 'transact':1548,1551,1625,1626,1660,1668,1674,1703,1714,1728 'tree':150,413,1790 'trgm':1881 'trigger':1336,1380,1414,1823 'trigram':170 'ts':208 'tune':27,442,460,1317,1467,1829 'tup':1052,1072,1085,1117,1120,1125,1129,1132,1150,1156,1184,1187,1428 'tupl':1351,1378,1410,1418,1451 'type':144,182,359,1224,1615,1787 'typic':1584 'u':280,710,785 'u.id':275,712,787 'u.name':277,704,779 'unbound':578 'update/delete':1464 'uri':57 'usag':282,632 'use':2,176,191,206,262,360,385,394,419,474,498,505,536,544,569,622,639,650,1162,1168,1574,1585,1666,1700,1724,1913 'user':111,137,225,279,479,503,709,784,1034,1076,1145,1192 'v3':117,1842 'vacuum':1337,1345,1364,1371,1373,1400,1420,1423,1453,1475,1485,1505,1805 'valid':470,613 'verbos':300 'verifi':488,619 'vip':1578 'vs':1166,1529,1661 'wait':1222,1225 'wal':1806 'watchdog':1577 'where/join/order':416 'wiki.postgresql.org':1909 'window':1773 'work':330,335,463 'worker':1518,1522 'workflow':350,1943 'write':4,82,383,523 'www.postgresql.org':1907 'www.postgresql.org/docs/current/':1906 'yes':1576 'zero':1899 'zero-downtim':1898","prices":[{"id":"11c429b7-8e8d-4897-b09e-45815f27c939","listingId":"bd3c2529-c63e-4b5e-beba-b1901cf140df","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"cofin","category":"flow","install_from":"skills.sh"},"createdAt":"2026-04-23T13:04:00.712Z"}],"sources":[{"listingId":"bd3c2529-c63e-4b5e-beba-b1901cf140df","source":"github","sourceId":"cofin/flow/postgres","sourceUrl":"https://github.com/cofin/flow/tree/main/skills/postgres","isPrimary":false,"firstSeenAt":"2026-04-23T13:04:00.712Z","lastSeenAt":"2026-05-18T19:07:38.609Z"}],"details":{"listingId":"bd3c2529-c63e-4b5e-beba-b1901cf140df","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cofin","slug":"postgres","github":{"repo":"cofin/flow","stars":11,"topics":["agent-skills","ai-agents","beads","claude-code","codex","context-driven-development","cursor","developer-tools","gemini-cli","opencode","plugin","slash-commands","spec-driven-development","subagents","tdd","workflow"],"license":"apache-2.0","html_url":"https://github.com/cofin/flow","pushed_at":"2026-04-27T19:07:26Z","description":"Context-Driven Development toolkit for AI agents — spec-first planning, TDD workflow, and Beads integration.","skill_md_sha":"fe7365617dfee23b7d555e357f474ae351dde797","skill_md_path":"skills/postgres/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cofin/flow/tree/main/skills/postgres"},"layout":"multi","source":"github","category":"flow","frontmatter":{"name":"postgres","description":"Use when writing PostgreSQL SQL, editing .sql files, psql commands, postgresql.conf, psycopg or asyncpg code, indexes, JSONB, PL/pgSQL, extensions, roles, RLS, replication, migrations, or query tuning."},"skills_sh_url":"https://skills.sh/cofin/flow/postgres"},"updatedAt":"2026-05-18T19:07:38.609Z"}}