# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview ProxySQL is a high-performance, protocol-aware proxy for MySQL (and forks like MariaDB, Percona Server) and PostgreSQL. Written in C++17, it provides connection pooling, query routing, caching, and monitoring. Licensed under GPL. ## Build Commands The build system is GNU Make-based with a three-stage pipeline: `deps` → `lib` → `src`. ```bash # Full release build (auto-detects -j based on nproc/hw.ncpu) make # Debug build (-O0, -ggdb, -DDEBUG) make debug # Build with ASAN (requires no jemalloc) NOJEMALLOC=1 WITHASAN=1 make build_deps_debug && make debug && make build_tap_test_debug # Build TAP tests (requires proxysql binary built first) make build_tap_tests # release make build_tap_test_debug # debug # Clean make clean # clean src/lib make cleanall # clean everything including deps # Build packages make packages ``` ### Feature Tiers The same codebase produces three product tiers via feature flags: | Tier | Flag | Version | Adds | |------|------|---------|------| | Stable | (default) | v3.0.x | Core proxy | | Innovative | `PROXYSQL31=1` | v3.1.x | FFTO, TSDB | | Plugin Chassis | `PROXYSQL40=1` | v4.0.x | Plugin loader + ABI (4-phase lifecycle, query-hook, shared Prometheus); builds and packages all v4.0 plugins including mysqlx and genai/MCP | **`PROXYSQL40=1` implies `PROXYSQL31=1` which implies `PROXYSQLFFTO=1` and `PROXYSQLTSDB=1`.** There is no separate `PROXYSQLGENAI` flag — `PROXYSQL40=1` builds and packages all v4.0 plugins (mysqlx, genai/MCP, anomaly detection). All AI/MCP/RAG/LLM features live in `plugins/genai/` and load as a `.so` at runtime. ### Build Flags - `NOJEMALLOC=1` — disable jemalloc - `WITHASAN=1` — enable AddressSanitizer (requires `NOJEMALLOC=1`) - `WITHGCOV=1` — enable code coverage - `PROXYSQLCLICKHOUSE=1` — enabled by default in current builds ## Testing Tests use TAP (Test Anything Protocol) with Docker-based backend infrastructure. ### Running TAP tests — DO NOT manually set up Docker containers **ALWAYS use `run-tests-isolated.bash`**. It handles infrastructure setup, ProxySQL start, test execution, and cleanup. Never manually create Docker networks, start containers, or run init scripts — the runner does all of that. ```bash # Set up infrastructure (backends + ProxySQL container) WORKSPACE=$(pwd) INFRA_ID=dev-$USER TAP_GROUP=mysql84-g1 test/infra/control/ensure-infras.bash # Run all tests for a TAP group WORKSPACE=$(pwd) INFRA_ID=dev-$USER TAP_GROUP=mysql84-g1 test/infra/control/run-tests-isolated.bash # Build test binaries first (requires proxysql binary) make build_tap_tests # release make build_tap_test_debug # debug ``` Available TAP groups are defined in `test/tap/groups/groups.json`. Group names follow the pattern `-g` (e.g., `mysql84-g1`, `legacy-g2`, `pgsql16-g1`). ### DO NOT - **DO NOT** manually create Docker networks (`docker network create`) - **DO NOT** manually start containers (`docker start`, `docker run`) - **DO NOT** run `docker-compose-init.bash` directly — use `ensure-infras.bash` - **DO NOT** symlink build artifacts between worktrees — build in each worktree separately - **DO NOT** copy source files between worktrees or repos - **DO NOT** run `cd test/tap/tests && make` and expect tests to pass without infrastructure ### Test file conventions Test files follow the naming pattern `test_*.cpp` or `*-t.cpp` in `test/tap/tests/`. Test binaries are built via a pattern rule in `test/tap/tests/Makefile`: `make -t` compiles `-t.cpp` into `-t`. No special Makefile target is needed for new tests — just add the `.cpp` file and register it in `groups.json`. ### Reporting CI/test failures **Test quality is paramount on this project. Never dismiss a CI failure as "pre-existing" or "flaky".** Those words are observations, not analyses, and using them as a conclusion lets real bugs survive. When CI fails on a branch or PR: 1. **Read the actual failure.** Open the failing test log, the proxysql server log it produced, and the test source. Identify the specific assertion, timeout, crash, or non-zero exit. Quote the relevant lines in your report. 2. **State the root cause, not the symptom.** "Test X failed" is a symptom. The root cause is *why* — a race condition, a stale fixture, a resource leak, a protocol regression, an env mismatch, etc. 3. **Separate two distinct questions** and answer both with evidence: - *Did the current change cause this failure?* — answer via commit-by-commit reasoning and code-path analysis, not just by comparing baseline pass/fail rates. - *Is this test broken regardless of the current change?* — independent question. A failure that pre-dates the change is still a problem to fix or file, not a reason to merge over. 4. **If the root cause cannot be determined within the session**, say so explicitly and recommend the next investigation step (re-run with logs, instrument the test, file a tracking issue). Do not paper over uncertainty with "flaky". 5. **A repeatedly failing test is a higher-priority bug, not a lower one.** Recurrence is evidence that the failure mode is reproducible — that is exactly what makes it fixable. ## Architecture ### Build Pipeline ``` deps/ → builds 25+ vendored dependencies as static libraries lib/ → compiles ~121 .cpp files into libproxysql.a src/main.cpp → links against libproxysql.a to produce the proxysql binary ``` ### Dual-Protocol Design MySQL and PostgreSQL share parallel class hierarchies with the same architecture but protocol-specific implementations: | Layer | MySQL | PostgreSQL | |-------|-------|------------| | Protocol | `MySQL_Protocol` | `PgSQL_Protocol` | | Session | `MySQL_Session` | `PgSQL_Session` | | Thread | `MySQL_Thread` | `PgSQL_Thread` | | HostGroups | `MySQL_HostGroups_Manager` | `PgSQL_HostGroups_Manager` | | Monitor | `MySQL_Monitor` | `PgSQL_Monitor` | | Query Processor | `MySQL_Query_Processor` | `PgSQL_Query_Processor` | | Logger | `MySQL_Logger` | `PgSQL_Logger` | ### Core Components - **Admin Interface** (`ProxySQL_Admin.cpp`, `Admin_Handler.cpp`) — SQL-based configuration via SQLite3 backend. Supports runtime config changes without restart. Schema versions tracked in `ProxySQL_Admin_Tables_Definitions.h`. - **HostGroups Manager** — Routes connections based on hostgroup assignments. Supports master-slave, Galera, Group Replication, and Aurora topologies. - **Query Processor** — Parses queries, matches against routing rules, handles query caching via `Query_Cache`. - **Monitor** — Health-checks backends for replication lag, read-only status, and connectivity. - **Threading** — Event-based I/O using libev. `Base_Thread` base class with protocol-specific thread managers. - **HTTP/REST** (`ProxySQL_HTTP_Server`, `ProxySQL_RESTAPI_Server`) — Metrics and management endpoints. ### Key Dependencies (in deps/) - `jemalloc` — memory allocator - `sqlite3` — admin config storage - `mariadb-client-library` — MySQL protocol - `postgresql` — PostgreSQL protocol - `re2`, `pcre` — regex engines - `libev` — event loop - `libinjection` — SQL injection detection - `lz4`, `zstd` — compression - `curl`, `libmicrohttpd`, `libhttpserver` — HTTP - `prometheus-cpp` — metrics - `libscram` — SCRAM authentication ### Conditional Components - **FFTO** (Fast Forward Traffic Observer) — `MySQLFFTO.cpp`, `PgSQLFFTO.cpp` - **TSDB** — Time-series metrics with embedded dashboard - **ClickHouse** — Native ClickHouse protocol support - **GenAI / MCP / RAG / LLM** — Lives entirely in `plugins/genai/` as of the carve-out completed in Step 7. Loaded via `dlopen` when `plugins = (genai)` is configured in `proxysql.cnf`; not part of `libproxysql.a` or the `proxysql` binary. ## Code Layout - `include/` — All headers (.h/.hpp). Include guards use `#ifndef __CLASS_*_H`. - `lib/` — Core library sources (~121 files). One class per file typically. - `src/main.cpp` — Entry point, daemon init, thread spawning (~95K lines). - `test/tap/` — TAP test framework and tests. - `test/infra/` — Docker-based test environments. - `.github/workflows/` — CI/CD pipelines (selftests, TAP tests, package builds, CodeQL). **See `doc/GH-Actions/README.md` for the architecture overview** — ProxySQL uses a two-branch caller/reusable split (`CI-*.yml` on `v3.0`, `ci-*.yml` on the `GH-Actions` branch) and the doc is the authoritative reference for how it fits together. ## Agent Guidelines See `doc/agents/` for detailed guidance on working with AI coding agents: - `doc/agents/project-conventions.md` — ProxySQL-specific rules (directories, build, test harness, git workflow) - `doc/agents/task-assignment-template.md` — Template for writing issues assignable to AI agents - `doc/agents/common-mistakes.md` — Known agent failure patterns with prevention and detection ### Unit Test Harness Unit tests live in `test/tap/tests/unit/` and link against `libproxysql.a` via a custom test harness. Tests must use `test_globals.h` and `test_init.h` — see `doc/agents/project-conventions.md` for the full pattern. ## Coding Conventions - Class names: `PascalCase` with protocol prefixes (`MySQL_`, `PgSQL_`, `ProxySQL_`) - Member variables: `snake_case` - Constants/macros: `UPPER_SNAKE_CASE` - C++17 required; conditional compilation via `#ifdef PROXYSQL31`, `#ifdef PROXYSQL40`, `#ifdef PROXYSQLFFTO`, `#ifdef PROXYSQLTSDB`, `#ifdef PROXYSQLCLICKHOUSE`. (`PROXYSQLGENAI` no longer guards any core code as of Step 7 of the GenAI plugin carve-out — it lives only inside `plugins/genai/` now.) - Performance-critical code — consider implications of changes to hot paths - RAII for resource management; jemalloc for allocation - Pthread mutexes for synchronization; `std::atomic<>` for counters