This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
The guidance in this CLAUDE.md applies to pgxntool's own source files and provides recommended best practices for projects using pgxntool. However, any agent working in an extension project should always defer to that project's own CLAUDE.md and instructions over anything stated here.
IMPORTANT: When creating commit messages, do not attribute commits to yourself (Claude). Commit messages should reflect the work being done without AI attribution in the message body. The standard Co-Authored-By trailer is acceptable.
pgxntool is NOT a standalone project. It is a meta-framework that exists ONLY to be embedded into PostgreSQL extension projects via git subtree. This repo cannot be built, tested, or run directly.
Think of it like this: pgxntool is to PostgreSQL extensions what a Makefile template library is to C projects - it's infrastructure code that gets copied into other projects, not a project itself.
This directory contains ONLY files that get embedded into extension projects. When extension developers run git subtree add, they pull the entire pgxntool directory into their project.
ABSOLUTE RULE: NO temporary files, scratch work, or development tools may be added to this directory.
Examples of what NEVER belongs here:
- Temporary files (scratch notes, test output, debugging artifacts)
- Development scripts or tools (these go in pgxntool-test/)
- Planning documents (PLAN-*.md files go in pgxntool-test/)
- Any file you wouldn't want in every extension project that uses pgxntool
CLAUDE.md exception: CLAUDE.md exists here for AI assistant guidance, but is excluded from distributions via .gitattributes export-ignore. Same with .claude/ directory.
Why this matters: Any file you add here will be pulled into hundreds of extension projects via git subtree. Keep this directory lean and clean.
CRITICAL: All development work on pgxntool should be done from the pgxntool-test repository, NOT from this repository.
For complete development workflow documentation, see: https://github.com/Postgres-Extensions/pgxntool-test
This codebase uses a two-repository pattern:
- pgxntool/ (this repo) - The framework code that gets embedded into extension projects
- pgxntool-test - The test harness that validates pgxntool functionality
For development and testing workflow, see: https://github.com/Postgres-Extensions/pgxntool-test
Extension projects include pgxntool via git subtree:
git subtree add -P pgxntool --squash git@github.com:decibel/pgxntool.git release
pgxntool/setup.shAfter setup, their Makefile typically contains just:
include pgxntool/base.mk- Processes
META.in.json(template with placeholders/empty values) - Strips out X_comment fields and empty values
- Produces clean
META.json
- Parses
META.jsonusingJSON.sh(a bash-based JSON parser) - Generates
meta.mkwith Make variables:PGXN- distribution namePGXNVERSION- version numberEXTENSIONS- list of extensions providedEXTENSION_*_VERSION- per-extension versionsEXTENSION_VERSION_FILES- auto-generated versioned SQL files
base.mkincludesmeta.mkvia-include
base.mk provides a complete PGXS-based build system:
- Auto-detects extension SQL files in
sql/ - Auto-detects C modules in
src/*.c - Auto-detects tests in
test/sql/*.sql - Auto-generates versioned extension files (
extension--version.sql) - Handles Asciidoc → HTML conversion
- Integrates with PGXN distribution format
- Manages git tagging and release packaging
Projects using pgxntool follow this layout:
project/
├── Makefile # include pgxntool/base.mk
├── META.in.json # Template metadata (customize for your extension)
├── META.json # Auto-generated from META.in.json
├── extension.control # Standard PostgreSQL control file
├── pgxntool/ # This repo, embedded via git subtree
├── sql/
│ └── extension.sql # Base extension SQL
├── src/ # Optional C code (*.c files)
├── test/
│ ├── deps.sql # Load extension and test dependencies
│ ├── sql/*.sql # Test SQL files
│ └── expected/*.out # Expected test outputs
└── doc/ # Optional docs (*.adoc, *.asciidoc)
These are the commands extension developers use (documented for context):
make # Build extension (generates versioned SQL, docs)
make test # Full test: testdeps → install → installcheck → show diffs
make results # Run tests and update expected output files
make html # Generate HTML from Asciidoc sources
make tag # Create git branch for current META.json version
make dist # Create PGXN .zip (auto-tags, places in ../)
make pgtle # Generate pg_tle registration SQL (see pg_tle Support below)
make check-pgtle # Check pg_tle installation and report version
make install-pgtle # Install pg_tle registration SQL files into database
make pgxntool-sync # Update to latest pgxntool via git subtree pullNEVER use make installcheck directly. Always use make test instead. The make test target ensures:
- Clean builds before testing
- Proper test isolation
- Correct test dependency installation
- Proper cleanup and result comparison
Database Connection Requirement: PostgreSQL must be running before executing make test. If you get connection errors (e.g., "could not connect to server"), stop and ask the user to start PostgreSQL.
Claude Code MUST NEVER run make results. This target updates test expected output files and requires manual human verification of test changes before execution.
Claude Code MUST NEVER modify files in test/expected/. These are expected test outputs that define correct behavior and must only be updated through the make results workflow.
The workflow is:
- Human runs
make testand examines diffs - Human manually verifies changes are correct
- Human manually runs
make resultsto update expected files
pgxntool uses PostgreSQL's pg_regress test framework:
- Actual test output: Written to
test/results/directory - Expected output: Stored in
test/expected/directory - Test comparison: pg_regress compares actual vs expected and generates diffs;
make testdisplays them - Updating expectations:
make resultscopiestest/results/→test/expected/
When tests fail, examine the diff output carefully. The actual test output in test/results/ shows what your code produced, while test/expected/ shows what was expected.
MAJORVER= version × 10 (e.g., 9.6 → 96, 13 → 130)- Tests use
--load-language=plpgsqlfor versions < 13 - Version detection via
pg_config --version
- Tests in
test/sql/*.sql, outputs compared totest/expected/*.out - Setup via
test/pgxntool/setup.sql(loads pgTap and deps.sql) .IGNORE: installcheckallowsmake testto handle errors (show diffs, then exit with error status)make resultsupdates expected outputs after test runs
- Auto-detects
asciidoctororasciidoc - Generates HTML from
*.adocand*.asciidocin$(DOC_DIRS) - HTML required for
make dist, optional formake install - Template-based rules via
ASCIIDOC_template
make distcreates../PGXN-VERSION.zip- Always creates git branch tag matching version
- Uses
git archiveto package - Validates repo is clean before tagging
make pgxntool-syncpulls latest release- Multiple sync targets: release, stable, local variants
- Uses
git subtree pull --squash - Requires clean repo (no uncommitted changes)
pgxntool can generate pg_tle (Trusted Language Extensions) registration SQL for deploying extensions in AWS RDS/Aurora without filesystem access.
Usage: make pgtle or make pgtle PGTLE_VERSION=1.5.0+
Output: pg_tle/{version_range}/{extension}.sql
For version range details and API compatibility boundaries, see: pgtle_versions.md
Installation targets:
-
make check-pgtle- Checks if pg_tle is installed and reports the version. Reports version frompg_extensionif extension has been created, or newest available version frompg_available_extension_versionsif available but not created. Errors if pg_tle not available in cluster. AssumesPG*environment variables are configured. -
make install-pgtle- Auto-detects pg_tle version and installs appropriate registration SQL files. Updates or creates pg_tle extension as needed. Determines which version range files to install based on detected version. Runs all generated SQL files viapsqlto register extensions with pg_tle. AssumesPG*environment variables are configured.
Version notation:
X.Y.Z+means >= X.Y.ZX.Y.Z-A.B.Cmeans >= X.Y.Z and < A.B.C (note boundary)
Key implementation details:
- Script:
pgxntool/pgtle-wrap.sh(bash) - Parses
.controlfiles for metadata (NOT META.json) - Fixed delimiter:
$_pgtle_wrap_delimiter_$(validated not in source) - Each output file contains ALL versions and ALL upgrade paths
- Multi-extension support (multiple .control files)
- Output directory
pg_tle/excluded from git - Depends on
make allto ensure versioned SQL files exist first - Only processes versioned files (
sql/{ext}--{version}.sql), not base files
SQL file handling:
- Version files (
sql/{ext}--{version}.sql): Generated automatically bymake allfrom basesql/{ext}.sqlfile - Upgrade scripts (
sql/{ext}--{v1}--{v2}.sql): Created manually by users when adding new extension versions - The script ensures the default_version file exists if the base file exists (creates it from base file if missing)
- All version files and upgrade scripts are discovered and included in the generated pg_tle registration SQL
Dependencies: Generated files depend on:
- Control file (metadata source)
- All SQL files (sql/{ext}--*.sql) - must run
make allfirst - Generator script itself
Limitations:
- No C code support (pg_tle requires trusted languages only)
- PostgreSQL 14.5+ required (pg_tle not available on earlier versions)
- Empty Variables: If
DOCSorMODULESis empty, base.mk sets to empty to prevent PGXS errors - testdeps Pattern: Never add recipes to
testdeps- create separate target and make it a prerequisite - META.json is Generated: Always edit
META.in.json, neverMETA.jsondirectly - Control File Versions: No automatic validation that
.controlmatchesMETA.jsonversion - PGXNTOOL_NO_PGXS_INCLUDE: Setting this skips PGXS inclusion (for special scenarios)
- Distribution Placement:
.zipfiles go in parent directory (../) to avoid repo clutter
- setup.sh - Initializes pgxntool in a new extension project (copies templates, creates directories)
- build_meta.sh - Strips empty fields from META.in.json to create META.json
- meta.mk.sh - Parses META.json via JSON.sh and generates meta.mk with Make variables
- JSON.sh - Third-party bash JSON parser (MIT licensed)
- safesed - Utility for safe sed operations
- pgxntool-test - Test harness for validating pgxntool functionality: https://github.com/Postgres-Extensions/pgxntool-test
- Never produce any kind of metrics or estimates unless you have data to back them up. If you do have data you MUST reference it.