{"id":47711953,"url":"https://github.com/burnside-project/pg-stress","last_synced_at":"2026-04-08T00:01:02.291Z","repository":{"id":348580707,"uuid":"1198712668","full_name":"burnside-project/pg-stress","owner":"burnside-project","description":" A PostgreSQL OLTP stress testing and AI-powered advisory platform with 10+ coordinated Docker services.No schema to configure. Point it at your database — pg-stress introspects the schema, discovers relationships, classifies tables, and generates realistic ORM and SQL load patterns automatically.","archived":false,"fork":false,"pushed_at":"2026-04-06T21:18:39.000Z","size":4701,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-06T23:02:46.460Z","etag":null,"topics":["ai-agents","claude","postgresql"],"latest_commit_sha":null,"homepage":"https://burnsideproject.ai","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/burnside-project.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-01T17:27:06.000Z","updated_at":"2026-04-06T21:18:45.000Z","dependencies_parsed_at":null,"dependency_job_id":"f5294245-7130-416e-b313-ff79bb77999e","html_url":"https://github.com/burnside-project/pg-stress","commit_stats":null,"previous_names":["burnside-project/pg-stress"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/burnside-project/pg-stress","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/burnside-project%2Fpg-stress","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/burnside-project%2Fpg-stress/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/burnside-project%2Fpg-stress/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/burnside-project%2Fpg-stress/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/burnside-project","download_url":"https://codeload.github.com/burnside-project/pg-stress/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/burnside-project%2Fpg-stress/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31533824,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"ssl_error","status_checked_at":"2026-04-07T16:28:06.951Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","claude","postgresql"],"created_at":"2026-04-02T18:36:16.849Z","updated_at":"2026-04-08T00:01:02.279Z","avatar_url":"https://github.com/burnside-project.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- Logo placeholder --\u003e\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003epg-stress\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  Point at any PostgreSQL \u0026rarr; auto-discover schema \u0026rarr; stress test \u0026rarr; Claude-powered advisory.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/burnside-project/pg-stress/actions/workflows/ci-cd.yml\"\u003e\u003cimg src=\"https://github.com/burnside-project/pg-stress/actions/workflows/ci-cd.yml/badge.svg\" alt=\"CI/CD\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/burnside-project/pg-stress/releases/latest\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/burnside-project/pg-stress?include_prereleases\u0026label=release\" alt=\"Release\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-Apache%202.0-blue\" alt=\"License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://claude.ai\"\u003e\u003cimg src=\"https://img.shields.io/badge/AI%20Powered-Claude%20Code-blueviolet\" alt=\"AI Powered\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## What is pg-stress?\n\nA **100% local, one-off** stress testing platform for any PostgreSQL database.\nNo models to write. No queries to define. No schema to configure. No data leaves\nyour machine.\n\nPoint it at your database — pg-stress introspects the schema, discovers relationships,\nclassifies tables, and generates realistic ORM and SQL load patterns automatically.\nAfter the test, Claude analyzes the diagnostics and gives tuning advice.\n\n### Core Features\n\n| Feature | Description |\n|---------|-------------|\n| **Named Test Runs** | Start, stop, and compare tests. Every test resets to a known baseline (production dump). Before/after snapshots saved to SQLite. |\n| **Schema Graph (NetworkX)** | Introspects tables, FKs, indexes on startup. Builds a directed graph cached in SQLite — instant load on restart, no repeated introspection. Scales to 5,000+ tables. |\n| **Cascading Inject** | Inject rows into a parent table and automatically inject proportional child rows following the FK graph. Ratios calculated from existing data. Works with any schema — ecommerce, CRM, healthcare. |\n| **WHAT IF Scenarios** | One scenario at a time, on top of active load generators: inject rows (with cascade), bulk update, connection spike, growth ladder. Live table stats with row deltas and spinning progress indicator. |\n| **Production Query Replay** | Import real queries from `pg_stat_statements` or SQL files. Replay at configurable concurrency alongside generators. Per-query timing (avg/min/max ms, errors). |\n| **Live Activity Ticker** | Real queries from `pg_stat_activity` updated every 2s, color-coded by type (SELECT, INSERT, JOIN, EXISTS), with table names and durations. On both portals. |\n| **10 ORM Patterns** | N+1, eager load (join/subquery/selectin), bulk insert, pagination, aggregation, EXISTS filter, relationship JOIN — applied to YOUR schema via SQLAlchemy automap. |\n| **AI Analyzer** | Claude reads 11 PostgreSQL diagnostic datasets. Returns tuning advice, query fixes, N+1 detection, capacity predictions. Executive summary compares across test runs. |\n| **3-Day Capacity Planning** | Day 1: baseline. Day 2: 2x growth. Day 3: with fixes. Day 4: compare all 3 reports. Hand off to pg-deploy for right-sized infrastructure. |\n| **DuckDB Analytics** | Fast time-series aggregations on SQLite metrics. Avg/peak TPS, cache ratio, growth rate — computed on demand, no import step. |\n| **PostgreSQL Config Viewer** | Live PG settings displayed on the dashboard — shared_buffers, work_mem, max_connections, etc. Deliberately modest defaults so AI Analyzer can recommend improvements. |\n| **Dual Portal UI** | Control Panel (`:3100`) for orchestration + Metrics Dashboard (`:8200`) for real-time charts. Cross-linked sidebars. Light mode matching Burnside Project style. |\n| **Fully Local** | SQLite for metrics, DuckDB for analytics, NetworkX for schema graph, PostgreSQL for stress target. Nothing leaves your network. |\n| **Managed PostgreSQL Support** | Load production data into a private managed PostgreSQL instance, deploy pg-stress on a test host in the same VPC/VNet. No public internet exposure. |\n\n### pg-stress vs pg-collector\n\n| | pg-stress | pg-collector |\n|---|---|---|\n| **When** | One-off, before a change or event | Always running |\n| **Where** | Disposable test server (Docker) | Production |\n| **Data** | 100% local (SQLite + DuckDB) | Shipped to warehouse |\n| **Purpose** | \"What will happen?\" | \"What is happening?\" |\n| **Output** | AI advisory report | Metric time-series |\n| **Duration** | Minutes to hours | Ongoing |\n\n## How It Works\n\n```\nYOUR DATABASE (any schema, any size)\n     │\n     ▼\nINTROSPECT ─── tables, FKs, indexes, row counts, types\n     │          classify: entity | transactional | append_only | lookup | hierarchical\n     │          NetworkX directed graph cached in SQLite (instant on restart)\n     ▼\nREFLECT ────── SQLAlchemy automap: ORM classes generated for every table\n     │          relationships auto-detected from FK constraints\n     ▼\nSTRESS ─────── 10 ORM patterns + raw SQL + production query replay\n     │          cascading inject follows FK graph with proportional ratios\n     │          WHAT IF scenarios on top of active generators\n     ▼\nCAPTURE ────── pg_stat_statements, table stats, cache ratio, locks, wait events\n     │          SQLite metrics (persistent), DuckDB analytics (on demand)\n     │          per-query replay timing, before/after snapshots per test run\n     ▼\nADVISE ─────── Claude analyzes diagnostics → tuning, query fixes, capacity predictions\n     │          executive summary across multiple test runs\n     │          deployment readiness report → hand off to pg-deploy\n```\n\n\u003e ### Control Panel (`:3100`) — Test runs, live activity, WHAT IF scenarios, AI analysis\n\u003e ![Control Panel](assets/control-panel-full.png)\n\n---\n\n\u003e ### Control Panel (`:3100`) — What if senerio stress\n\u003e ![Control Panel](assets/what-if.png)\n\u003e\n\u003e `http://\u003chost\u003e:3100` — Start/stop named tests, inject rows, run growth ladders,\n\u003e Introspects tables, FKs, indexes on startup. Builds a directed graph cached\n\u003e Inject rows into a parent table and automatically inject proportional child rows \n  following the FK graph. Ratios calculated from existing data. Works with any schema\n  ecommerce, CRM, healthcare\n\n---\n\n\u003e ### Metrics Dashboard (`:8200`) — Real-time charts, table growth, live queries\n\u003e ![Dashboard](assets/dashboard.png)\n\u003e\n\u003e `http://\u003chost\u003e:8200` — TPS, cache hit ratio, connections, table sizes with live\n\u003e growth deltas (+N/-N), locks, dead tuples. Live activity ticker shows every query\n\u003e running right now. Test run badge shows active test name and baseline.\n\n---\n\n\u003e ### Metrics Dashboard (`:8200`) — Get AI enabeled tuning advise\n\u003e ![Dashboard](assets/ai-analyzer.png)\n\u003e\n\u003e `http://\u003chost\u003e:8200` —  After the test, Claude analyzes the diagnostics and gives tuning advice.\n\u003e \n\u003e You need Claude AI API Key \n\n---\n\n\u003e ### Metrics Dashboard (`:8200`) — View Real-time Postgresql Config\n\u003e ![Dashboard](assets/config-loader.png)\n\u003e\n\u003e `http://\u003chost\u003e:8200` — View realtime Postgresql Config Parameters\n\u003e \n\u003e No need to dig into your config file. Refine your config prams and restart TEST server to shadow your Production Server Configs!\n\n## Install\n\nEvery push to `main` builds multi-arch Docker images (`linux/amd64` + `linux/arm64`)\nand publishes them to GHCR with an auto-incremented release candidate tag.\n\n```bash\n# Pull latest RC images\nfor svc in load-generator load-generator-orm pgbench-runner dashboard truth-service; do\n  docker pull ghcr.io/burnside-project/pg-stress/${svc}:rc-latest\ndone\n```\n\nOr pin to a specific version:\n\n```bash\ndocker pull ghcr.io/burnside-project/pg-stress/load-generator:v1.0.0-rc16\n```\n\nSee [Releases](https://github.com/burnside-project/pg-stress/releases) for all versions and changelogs.\n\n## Quickstart\n\n### Path A: I have production data\n\n\u003e pg-stress runs its own PostgreSQL container — it does **not** connect to your\n\u003e live production database. Instead, you export a dump and import it locally.\n\n**Step 1 — Export a dump from production** (run against your production DB):\n\n```bash\npg_dump -Fc -h prod-host -U prod_user my_production_db \u003e production.dump\n```\n\n**Step 2 — Clone and configure:**\n\n```console\n$ git clone https://github.com/burnside-project/pg-stress.git\n$ cd pg-stress \u0026\u0026 cp .env.example .env\n```\n\nEdit `.env`:\n\n```bash\nPG_DATABASE=my_production_db       # must match the DB name in your dump\nSEED_SCHEMA=false                  # skip built-in e-commerce schema\n```\n\n**Step 3 — Import and start:**\n\n```console\n$ make import DUMP=production.dump\n$ make up INTENSITY=medium\n```\n\npg-stress restores your dump into the local container, introspects your schema,\nand starts generating load automatically.\n\n### Path B: I don't have production data\n\n```console\n$ git clone https://github.com/burnside-project/pg-stress.git\n$ cd pg-stress\n$ make up                        # Seeds 18-table e-commerce schema (~30M rows)\n```\n\nOpen `http://localhost:3100` — pg-stress auto-discovers your schema and starts generating load.\n\n## What Happens at Startup\n\npg-stress connects to PostgreSQL and introspects the schema automatically:\n\n```\n2026-04-01 10:00:01 INFO Introspecting database: production_db\n2026-04-01 10:00:01 INFO Found 42 tables\n2026-04-01 10:00:02 INFO Classification: entity=8 transactional=12 append_only=6 lookup=14 hierarchical=2\n2026-04-01 10:00:02 INFO Schema: 42 tables, 38 relationships, 24 FK chains\n2026-04-01 10:00:02 INFO Queryable: 30 tables, insertable: 18, updatable: 20, paginable: 26\n2026-04-01 10:00:02 INFO 5 workers running against 42 tables\n```\n\nNo configuration. No model definitions. Works with 5 tables or 500.\n\n## Monitoring the Stress Test\n\nOnce the stack is running, there are several ways to see what's happening.\n\n### Control Panel UI (`:3100`)\n\nThe primary interface. Shows database target, current intensity, service status,\nconnections, table counts, and active jobs. From here you can:\n\n- Switch intensity (Low / Medium / High)\n- Import a production dump (BYOD)\n- Inject rows into any table\n- Run bulk updates\n- Launch connection pressure tests\n- Start growth ladders\n- Trigger AI analysis\n\n### Metrics Dashboard (`:8200`)\n\nReal-time auto-refreshing charts and live activity feed:\n\n- **Live Activity Ticker** — real queries from `pg_stat_activity`, updated every 2s,\n  color-coded by type (SELECT, INSERT, JOIN, EXISTS, AGGREGATION), with duration and table name\n- **TPS** — transactions per second over time\n- **Cache hit ratio** — shared buffer effectiveness\n- **Active connections** — current vs max\n- **Table sizes** — growth over time\n- **Dead tuples** — autovacuum pressure\n\n### ORM Generator Health (`:9091/healthz`)\n\nShows per-pattern operation counts in real time:\n\n```json\n{\n  \"status\": \"running\",\n  \"uptime_s\": 725,\n  \"ops\": {\n    \"n_plus_1\": 9739,\n    \"eager_join\": 9833,\n    \"eager_subquery\": 6429,\n    \"eager_selectin\": 6473,\n    \"bulk_insert\": 3243,\n    \"orm_update\": 6389,\n    \"pagination\": 6444,\n    \"aggregation\": 6701,\n    \"exists_filter\": 6580,\n    \"relationship\": 3227,\n    \"errors\": 0\n  }\n}\n```\n\n### Control Plane API (`:8100`)\n\nREST API with Swagger docs at `/docs`. Key endpoints for monitoring:\n\n```bash\n# Stack status — services, DB size, connections, table row counts\ncurl http://\u003chost\u003e:8100/status\n\n# Current config — database target + intensity level\ncurl http://\u003chost\u003e:8100/config\n\n# Background job status\ncurl http://\u003chost\u003e:8100/jobs\n```\n\n### PostgreSQL Direct Queries\n\nConnect to the database and inspect what the stress test is doing:\n\n```bash\n# Top queries by total execution time\nmake pg-stat\n\n# Database and table sizes\nmake db-size\n\n# Or connect directly\ndocker compose exec postgres psql -U postgres -d \u003cyour_db\u003e\n```\n\nExample — top queries during a stress test against `soak_test`:\n\n```\n calls | total_ms | mean_ms | query\n-------+----------+---------+----------------------------------------------------\n  6792 |  2225923 |  327.73 | SELECT p.id, p.name, similarity(p.name, $1) AS ...\n   471 |  1308156 | 2777.40 | SELECT orders.id, orders.customer_id, orders.... (N+1)\n   532 |   484258 |  910.26 | SELECT date_trunc($1, placed_at) AS hour, count(*)...\n   454 |   172025 |  378.91 | SELECT public.order_items.id, ... (eager join)\n   557 |   146450 |  262.93 | SELECT p.id, count(oi.id) AS units_sold, sum(...)\n```\n\nThis tells you exactly which queries are consuming the most time — the same\nqueries Claude analyzes when you run `make analyze`.\n\n## Three Knobs\n\n### 1. Database Target (`.env`)\n\nThese configure the **local Docker container**, not a remote server:\n\n```bash\nPG_USER=postgres               # container Postgres user (default: postgres)\nPG_PASSWORD=postgres           # container Postgres password (default: postgres)\nPG_DATABASE=mydb               # database name — match your dump for Path A\nSEED_SCHEMA=false              # false when using your own imported dump\n```\n\n### 2. Intensity (CLI or UI)\n\n```bash\nmake up INTENSITY=low              # No chaos, 3-15 conns, safe for BYOD validation\nmake up INTENSITY=medium           # 25% chaos, 5-50 conns (default)\nmake up INTENSITY=high             # 50% chaos, 15-80 conns, finds breaking points\n```\n\n### 3. WHAT IF Scenarios (UI or API)\n\n| Action | What it tests |\n|--------|---------------|\n| Inject 10M rows | \"What if this table doubles?\" |\n| Bulk update 20M rows | \"What if we archive old data?\" |\n| 100 connections | \"What happens at peak traffic?\" |\n| Growth ladder 10→200 | \"At what point does it break?\" |\n\n## Schema Introspection\n\npg-stress discovers your schema and classifies every table:\n\n| Signal | Classification | Load Pattern |\n|---|---|---|\n| Has FK children + timestamps | **entity** | N+1, eager load, EXISTS filter |\n| Has status + updated_at | **transactional** | CRUD, status transitions |\n| Only created_at, no updates | **append_only** | Bulk insert, time-range queries |\n| Small, no FK children | **lookup** | Read-only via JOINs |\n| Self-referencing FK | **hierarchical** | Tree traversal |\n\nFK chains are discovered automatically and drive query patterns:\n\n```\ncustomers → orders → order_items → product_variants\n                  → payments\n                  → shipments\nproducts → variants → inventory\n```\n\n## 10 Auto-Generated ORM Patterns\n\nEach pattern is a generic template applied to **your** FK chains — not hardcoded queries:\n\n| Pattern | What it generates |\n|---------|-------------------|\n| **N+1 selects** | Load parent, lazy-load each child (any FK chain) |\n| **Eager joinedload** | Single SELECT with LEFT OUTER JOINs (any relationship) |\n| **Eager subqueryload** | Base SELECT + IN (subquery) for children |\n| **Eager selectinload** | Base SELECT + IN ($1,...,$N) literal list |\n| **Bulk INSERT** | Clone rows from any append-only table |\n| **ORM update** | Load-modify-save on any table with timestamps |\n| **Pagination** | LIMIT/OFFSET on any table with ordering columns |\n| **Aggregation** | count/sum/avg on any numeric column grouped by FK |\n| **EXISTS filter** | EXISTS subquery on any parent-child relationship |\n| **Relationship JOIN** | ORM-generated JOINs via any FK path |\n\n## Services\n\n| Service | Port | Description |\n|---------|------|-------------|\n| PostgreSQL 15 | 5434 | Database under test |\n| Raw SQL Generator (Go) | 9090 | 25+ hand-written OLTP operations, 6 chaos patterns |\n| ORM Generator (Python) | 9091 | 10 auto-discovered ORM patterns via schema introspection |\n| Dashboard | 8200 | Real-time charts: TPS, cache ratio, connections, table sizes |\n| Control Plane API | 8100 | REST API for WHAT IF scenarios, generator control, AI analysis |\n| Control Panel UI | 3100 | Browser-based dashboard with intensity controls |\n\nBoth portals link to each other via the left sidebar **Navigate** section. The sidebar\nalso includes a **Documentation** link to this repository.\n\n## PostgreSQL Configuration\n\nThe test container runs PostgreSQL 15 with these settings (configurable via `.env`).\nThese do not change during a test — only on container restart.\n\n| Setting | Value | What it controls |\n|---------|-------|-----------------|\n| `shared_buffers` | 256 MB | Shared memory for caching data pages |\n| `work_mem` | 16 MB | Memory per sort/hash operation |\n| `effective_cache_size` | 1 GB | Planner's cache size assumption |\n| `max_connections` | 200 | Maximum concurrent connections |\n| `maintenance_work_mem` | 128 MB | Memory for VACUUM, CREATE INDEX |\n| `wal_buffers` | 16 MB | WAL write buffer |\n| `max_wal_size` | 2 GB | WAL size before checkpoint |\n| `random_page_cost` | 1.1 | Cost estimate for random disk I/O (SSD optimized) |\n| `effective_io_concurrency` | 200 | Async I/O requests (SSD optimized) |\n| `checkpoint_completion_target` | 0.9 | Spread checkpoint writes over interval |\n| `autovacuum_max_workers` | 4 | Parallel autovacuum workers |\n| `autovacuum_naptime` | 30s | Time between autovacuum runs |\n| `shared_preload_libraries` | `pg_stat_statements` | Tracks query statistics |\n| `log_min_duration_statement` | 1000 ms | Log queries slower than 1s |\n\nThese are deliberately **modest defaults** so the AI Analyzer has room to recommend\nimprovements. The whole point is to stress the database, observe the bottlenecks,\nand get Claude to tell you what to tune.\n\n## AI Analyzer\n\nAfter a stress test, send diagnostics to Claude for expert analysis.\nThis is like [pg-collector](https://github.com/burnside-project/pg-collector) but\n**100% local** — no data leaves your machine. Designed for one-off tests, not\nproduction monitoring.\n\n### Setup\n\n```bash\n# Add your Anthropic API key to .env\necho 'ANTHROPIC_API_KEY=sk-ant-...' \u003e\u003e .env\n\n# Restart the control plane to pick up the key\ndocker compose up -d control-plane\n```\n\n### Run from CLI\n\n```bash\nmake analyze                       # Full report — health score, queries, tuning, capacity\nmake analyze-tuning                # PostgreSQL parameter tuning recommendations\nmake analyze-queries               # Query optimization + N+1 detection\nmake analyze-capacity              # Growth projections + capacity limits\n```\n\n### Run from UI\n\nOpen the Control Panel (`http://\u003chost\u003e:3100`), scroll to **AI Analyzer**, select a\nfocus area, and click **Run Analysis**. Results appear in the report viewer.\n\n### Run from API\n\n```bash\ncurl -X POST http://\u003chost\u003e:8100/analyze -H 'Content-Type: application/json' \\\n  -d '{\"focus\": null}'              # Full analysis\n\ncurl -X POST http://\u003chost\u003e:8100/analyze -H 'Content-Type: application/json' \\\n  -d '{\"focus\": \"tuning\"}'          # Tuning only\n\ncurl http://\u003chost\u003e:8100/analyze/latest  # View latest report\n```\n\n### What Gets Collected\n\nThe analyzer collects 11 diagnostic datasets from PostgreSQL before sending to Claude:\n\n| Dataset | Source | What it reveals |\n|---------|--------|-----------------|\n| Top queries | `pg_stat_statements` | Slowest queries by total time, calls, rows |\n| Cache misses | `pg_stat_statements` | Queries with worst shared buffer hit ratio |\n| Temp spills | `pg_stat_statements` | Queries writing temp files (work_mem too low) |\n| N+1 candidates | `pg_stat_statements` | High-call, low-row queries (ORM anti-pattern) |\n| Database stats | `pg_stat_database` | TPS, cache ratio, deadlocks, temp files |\n| Table stats | `pg_stat_user_tables` | Row counts, dead tuples, sequential scans |\n| Index stats | `pg_stat_user_indexes` | Index usage, scan counts |\n| Unused indexes | `pg_stat_user_indexes` | Indexes with zero scans (wasting write I/O) |\n| Connections | `pg_stat_activity` | Active, idle, idle-in-transaction by state |\n| Locks \u0026 waits | `pg_locks` + `pg_stat_activity` | Lock contention, wait events |\n| PG settings | `pg_settings` | Current configuration for tuning recommendations |\n\n### What Claude Reports\n\n| Focus | What you get |\n|-------|-------------|\n| **Full** | Health score (0-100), executive summary, top issues, query fixes, tuning, capacity |\n| **Tuning** | `shared_buffers`, `work_mem`, `effective_cache_size`, checkpoint, autovacuum recommendations |\n| **Queries** | N+1 detection, missing indexes, query rewrites, ORM anti-patterns |\n| **Capacity** | Growth projections, \"at what row count does it break\", scaling advice |\n\n## Commands\n\n| Command | What it does |\n|---------|-------------|\n| `make up` | Start core stack |\n| `make up INTENSITY=high` | Start with high intensity |\n| `make import DUMP=file` | BYOD: restore pg_dump |\n| `make up-orm` | Add ORM load generator |\n| `make up-full` | Start everything |\n| `make down` | Stop and remove volumes |\n| `make pg-stat` | Top 20 queries by execution time |\n| `make db-size` | Database and table sizes |\n| `make analyze` | Claude AI analysis (full) |\n| `make analyze-tuning` | AI focused on PG tuning |\n| `make healthz` | Check all services |\n| `make report` | Collect comprehensive report |\n| `make clean` | Stop, remove volumes and output |\n\n## Test Runs\n\nEvery test starts from a **known baseline** — a production dump that defines the starting state.\nThe database is reset before each run so results are reproducible and comparable.\n\n```\n1. Import baseline     →  pg_restore production.dump (one time)\n2. Start test          →  Name it, pick intensity, DB resets to baseline\n3. Stress + observe    →  ORM/SQL generators run, inject rows, watch metrics\n4. Stop \u0026 save         →  Before/after snapshot saved to SQLite\n5. Compare             →  View any past test, compare across runs\n```\n\n### From the UI\n\nOpen `http://\u003chost\u003e:3100`, go to **Test Run** section:\n1. Enter a name (e.g., `baseline-medium`, `after-btree-index`)\n2. Select intensity (Low / Medium / High)\n3. Check \"Reset database to baseline\" and provide the dump path\n4. Click **Start Test**\n\n### From the API\n\n```bash\ncurl -X POST http://\u003chost\u003e:8100/tests/start \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"name\":\"baseline-medium\",\"intensity\":\"medium\",\"baseline_dump\":\"/tmp/soak_test.dump\"}'\n\ncurl -X POST http://\u003chost\u003e:8100/tests/stop       # Stop and save\ncurl http://\u003chost\u003e:8100/tests                     # List all tests\ncurl http://\u003chost\u003e:8100/tests/active              # Get active test\n```\n\n### Storage\n\n| Data | Storage | Persists? |\n|------|---------|-----------|\n| Baselines (dump metadata) | SQLite | Yes |\n| Test runs (name, config, before/after) | SQLite | Yes |\n| Metrics time-series (per test run) | SQLite | Yes |\n| Cross-run analytics | DuckDB (reads SQLite) | Computed on demand |\n| AI reports | JSON + Markdown files | Yes |\n\n## Runbook\n\n### Full stress test with AI analysis\n\n```bash\n# 1. Clone and configure\ngit clone https://github.com/burnside-project/pg-stress.git\ncd pg-stress \u0026\u0026 cp .env.example .env\n\n# 2. Edit .env\nPG_HOST=10.29.29.214              # server identity (displayed in UI)\nPG_DATABASE=my_production_db      # match your dump name\nSEED_SCHEMA=false                 # skip built-in schema\nANTHROPIC_API_KEY=sk-ant-...      # for AI analysis\n\n# 3. Import production data\nmake import DUMP=production.dump\n\n# 4. Start with ORM generator\nmake up-orm INTENSITY=medium\n\n# 5. Monitor\nopen http://localhost:3100          # Control Panel — intensity, inject, WHAT IF\nopen http://localhost:8200          # Dashboard — real-time charts\n\n# 6. Run stress scenarios from the UI or CLI\ncurl -X POST http://localhost:8100/inject \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"table\":\"orders\",\"rows\":5000000}'\n\ncurl -X POST http://localhost:8100/ladder \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"steps\":[10,25,50,100,200],\"phase_duration\":180,\"mode\":\"mixed\"}'\n\n# 7. AI analysis\nmake analyze                        # Full report\nmake analyze-tuning                 # Just PG parameter tuning\nmake analyze-queries                # Just query optimization\n\n# 8. Collect raw report\nmake report                         # Saves to out/report-\u003ctimestamp\u003e/\n\n# 9. Cleanup\nmake down                           # Stop and remove volumes\n```\n\n### Quick validation (no production data)\n\n```bash\ngit clone https://github.com/burnside-project/pg-stress.git\ncd pg-stress\nmake up                             # Seeds 18-table e-commerce (~30M rows)\n# Wait ~10 min for seeding, then:\nopen http://localhost:3100\n```\n\n### Remote deployment\n\n```bash\n# Deploy to a remote server\nmake deploy DEPLOY_HOST=4           # SSH alias\n\n# Or deploy full stack\nmake deploy-full DEPLOY_HOST=4\n\n# Run pgbench on remote\nmake bench-remote DEPLOY_HOST=4\n\n# Collect report from remote\nmake report-remote DEPLOY_HOST=4\n```\n\n## Documentation\n\n| Doc | Description |\n|-----|-------------|\n| [How It Works](docs/01-how-it-works.md) | Introspect → reflect → generate load pipeline |\n| [Quickstart](docs/02-quickstart.md) | BYOD and seed paths, verification steps |\n| [Schema Introspection](docs/03-introspection.md) | What gets discovered, table classification, FK chains |\n| [Control Plane](docs/04-control-plane.md) | API endpoints, intensity presets, WHAT IF operations |\n| [Configuration](docs/05-configuration.md) | All environment variables |\n| [Releases \u0026 CI/CD](docs/06-releases.md) | Automated pipeline, versioning, Docker images, promoting RCs |\n\n## Production Query Replay\n\nImport your actual production queries and replay them against the test database\nunder load. This bridges the gap between \"random stress\" and \"how will MY queries\nbehave?\"\n\n### Import queries from production\n\n```bash\n# On your production server — export top 50 queries:\npsql -c \"SELECT query, calls, mean_exec_time, rows \\\n         FROM pg_stat_statements \\\n         ORDER BY total_exec_time DESC LIMIT 50\" --format=json \u003e queries.json\n\n# Upload to pg-stress:\ncurl -X POST http://\u003chost\u003e:8100/queries/import-stats \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"name\":\"prod-top-50\",\"queries\":'$(cat queries.json)'}'\n```\n\nOr use the Control Panel UI — paste the JSON directly.\n\n### Replay under load\n\n```bash\n# Start replay at 10 concurrent connections:\ncurl -X POST http://\u003chost\u003e:8100/replay/start \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"query_set_id\":\"\u003cset-id\u003e\",\"concurrency\":10,\"duration_s\":3600}'\n\n# Check per-query timing:\ncurl http://\u003chost\u003e:8100/replay/status\n\n# Stop and save results:\ncurl -X POST http://\u003chost\u003e:8100/replay/stop\n```\n\n### 3-Day Capacity Planning Workflow\n\n```\nDay 1: \"What do I have today?\"\n  → Reset to baseline → Replay production queries at 1x → Medium intensity → 24h\n  → Stop → Claude generates Report 1\n\nDay 2: \"What breaks at 2x scale?\"\n  → Reset to baseline → Inject 2x data → Replay at 2x frequency → High intensity → 24h\n  → Stop → Claude generates Report 2\n\nDay 3: \"Do the fixes work?\"\n  → Reset to baseline → Inject 2x data → Apply recommended indexes/config → 24h\n  → Stop → Claude generates Report 3\n\nDay 4: Executive Summary\n  → Compare all 3 reports → Deployment readiness recommendation\n  → Hand off to pg-deploy for right-sized infrastructure\n  → Hand off to pg-collector for ongoing monitoring\n```\n\n## Burnside Project Product Suite\n\n```\npg-stress (Day 0)          pg-deploy (Day 1)         pg-collector (Day 30+)\n\"What will happen?\"        \"Right-size it\"           \"What is happening?\"\n       │                        │                          │\n       ▼                        ▼                          ▼\n  Capacity planning    →   Deploy with          →   Production monitoring\n  Query replay             confidence               Drift detection\n  AI recommendations       PG config tuning          Predictive alerts\n  Right-sizing report      Infrastructure spec       Prescriptive tuning\n```\n\n| Product | Phase | Purpose | Duration |\n|---------|-------|---------|----------|\n| **[pg-stress](https://github.com/burnside-project/pg-stress)** | Pre-deploy | Capacity planning, what-if, query replay | Days (one-off) |\n| **pg-deploy** | Deploy | Infrastructure provisioning, PG config | Minutes (one-off) |\n| **[pg-collector](https://github.com/burnside-project/pg-collector)** | Post-deploy | Production monitoring, prediction, tuning | Ongoing |\n| **[pg-warehouse](https://github.com/burnside-project/pg-warehouse)** | Analytics | Historical trends, cross-system analysis | Ongoing |\n\n## License\n\n[Apache License 2.0](LICENSE) -- Copyright 2025-2026 [Burnside Project](https://burnsideproject.ai)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fburnside-project%2Fpg-stress","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fburnside-project%2Fpg-stress","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fburnside-project%2Fpg-stress/lists"}