DDX for PostgreSQL — How To Use Each Endpoint

Complete setup and usage guides for accessing PostgreSQL mailing lists and repositories.

For LLM clients: see /llms.txt for a structured index of all programmatic interfaces, suitable for autonomous agents that need to bootstrap context about pg.ddx.io quickly.

OVERVIEW

DDX for PostgreSQL offers multiple protocols to access the same data. Choose the one that fits your workflow:

1. IMAP — Email Client Access

Purpose: Read mailing lists in your email client

IMAP treats each PostgreSQL mailing list as an IMAP folder. Once connected, you can browse, search, and read messages directly in Thunderbird, Apple Mail, Outlook, or any IMAP-compatible email client.

Setup

1. Get the server address:
imap.pg.ddx.io:993 (SSL/TLS) or imap.pg.ddx.io:143 (STARTTLS)
2. Open your email client and add a new account:
  • Thunderbird: File → New → Existing Mail Account → Enter any username/password → Configure manually
  • Apple Mail: Mail → Preferences → Accounts → + → Other Mail Account
  • Outlook: File → Account Settings → Account Settings → New → More Options
3. Configure account settings:
Server: imap.pg.ddx.io Port: 993 (SSL) or 143 (STARTTLS) Username: (any name, e.g., "postgres") Password: (any password, e.g., "readonly") Security: SSL/TLS or STARTTLS
4. Subscribe to mailing lists: Once connected, you'll see all 54 PostgreSQL mailing lists as folders:
pgsql-hackers pgsql-general pgsql-bugs pgsql-admin pgsql-performance ... (47 more)
Click "Subscribe" to add them to your folder list. Start with pgsql-general (most active, general discussion).

Usage

Example 1: Browse recent discussions

1. Click "pgsql-hackers" folder

2. Your email client shows the newest messages first

3. Click a message to read the full thread

Example 2: Search across a mailing list

1. In Thunderbird: right-click a folder → Search Messages

2. Search for: "VACUUM performance" across pgsql-performance

3. Results show all matching messages with context

Example 3: Get notifications

1. Set your client to check for new mail every 1 hour (Settings)

2. Enable notifications when new messages arrive

3. You'll get alerts for new pgsql-hackers discussions

Tips

2. POP3 — Download and Keep Locally

Purpose: Download mailing list messages to your computer permanently

POP3 downloads messages and removes them from the server. Use this if you want to keep a local archive of PostgreSQL discussions.

Setup

1. Server address:
pop.pg.ddx.io:995 (SSL) or pop.pg.ddx.io:110 (STARTTLS)
2. Email client configuration:
Server: pop.pg.ddx.io Port: 995 (SSL) or 110 (STARTTLS) Username: <UUID>@<newsgroup>[.<slice>][?initial_limit=N&limit=N] Password: anonymous Leave email on server: YES (to keep archival copy)

Username format is required and strict. The server replies -ERR no UUID@ in mailbox name if the <UUID>@ prefix is missing.

  • UUID: any 32-hex-digit identifier, dashes optional. It is an opaque per-client tracking ID, not a credential — pick one once and reuse it. Example: deadbeefdeadbeefdeadbeefdeadbeef or dead-beef-dead-beef-dead-beef-dead-beef.
  • newsgroup: the inbox to read, e.g. pgsql.hackers, pgsql.general, pgsql.bugs.
  • .slice (optional): integer slice number; omit for the latest slice.
  • ?initial_limit=N&limit=N (optional): cap the number of messages returned.
  • Password: must be the literal string anonymous.

Example username: deadbeefdeadbeefdeadbeefdeadbeef@pgsql.hackers

Usage

Set your client to check every 24 hours. All new messages download and stay on your computer. Good for backup and offline research.

3. NNTP — Newsreader Access

Purpose: Access mailing lists via a classic NNTP newsreader

If you use a newsreader (Thunderbird, Usenet clients), connect via NNTP. Each mailing list appears as a newsgroup.

Setup

1. Server address:
nntp.pg.ddx.io:563 (TLS) ← recommended nntp.pg.ddx.io:119 (plain text)

In Thunderbird, tick Use secure connection (SSL) and set the port to 563. No username or password is needed.

2. Add newsserver to your NNTP client:
  • Thunderbird: Edit → Preferences → Network & Storage → Newsgroup Servers → Add
  • Other newsreaders: Add server with the address above
3. Subscribe to newsgroups:
pgsql-hackers pgsql-general pgsql-bugs (etc.)

Note: Newsgroup names use hyphens, not dots.

Usage

Read and search the lists as you would any newsgroup. The server is read-only: it answers POST with 440 posting not allowed. To take part in a discussion, reply to the list by email.

4. Git — Clone a Mailing List as Repository

Purpose: Access mailing list history as a git repository for scripting/analysis

Clone any PostgreSQL mailing list as a git repository. Each message is a commit. Use this for data analysis, historical research, or building tools.

What these repositories actually are. The git URLs under /m/<inbox>.git are public-inbox v2 archives of mailing-list traffic. They are not mirrors of the upstream PostgreSQL source tree. Each commit is one email; the working tree contains the message's metadata and body. To clone the actual PostgreSQL source code or any other upstream project repository, go to its canonical home (for PostgreSQL: https://git.postgresql.org/git/postgresql.git). pg.ddx.io does not re-publish project source repos.

Setup

1. Clone via HTTPS:
git clone https://pg.ddx.io/m/pgsql-hackers.git
2. Or via SSH (if you have SSH access):
git clone ssh://git@git.pg.ddx.io:22/pgsql-hackers.git

Usage

Example 1: Find all messages by a specific author
git log --author="Greg Burd" --oneline | head -20
Example 2: Find commits about query optimization
git log --all --grep="query.*optim" --oneline
Example 3: Analyze discussion trends over time
git log --format="%ai" | cut -d' ' -f1 | sort | uniq -c | sort -rn

(Shows how many messages per day)

Tips

4a. Feeds & notifications — be told when something new arrives

Purpose: Follow a list or a repository without polling pages

New mail on a list

https://pg.ddx.io/m/pgsql-hackers/new.atom newest messages (Atom) https://pg.ddx.io/m/pgsql-hackers/rss.xml the same, as RSS https://pg.ddx.io/m/pgsql-hackers/topics_new.atom new threads only https://pg.ddx.io/m/pgsql-hackers/topics_active.atom threads with fresh replies

Replace pgsql-hackers with any list on the archive. The message feeds hold the 25 newest messages; the two topic feeds hold 50 threads.

New commits in a repository

https://pg.ddx.io/gitweb/?p=postgresql.git;a=atom

The 50 newest commits, newest first. Each entry is the full commit message, so the Discussion:, Reviewed-by: and Backpatch-through: trailers are there, and the link opens the commit. a=rss returns the same feed. Swap postgresql for any project on /gitweb/ — pgbouncer, pgjdbc, pgpool2, psqlodbc and the rest.

Push, in a mail client (IMAP IDLE)

Connect to imap.pg.ddx.io:993 and open the highest-numbered folder of the list (for pgsql-hackers, pgsql-hackers.86). Each list is split into numbered folders, and new mail lands in the last one. The server supports IDLE, so a client left open is told about new mail as it arrives.

From code or an agent

Poll with a cursor so you only ever receive what is new. The get_new_messages MCP tool takes the last article_num you saw and returns what came after it, with has_more when there is another page:

{"name": "get_new_messages", "arguments": {"after": 4324863}}

A range of messages as a file

https://pg.ddx.io/m/pgsql-hackers/<from>-<to>.mbox.gz

The numbers are article numbers, which are global across all lists rather than counted from 1 within each one — so 1-100 usually returns nothing. Read a list's current range from /m/pgsql-hackers/info.json. For a whole list, clone it instead.

4b. Git commit search (REST) — the gitweb replacement for agents

Purpose: Search and fetch commits from the actual project git repositories (postgres core + ecosystem) as JSON

This is a fast, agent-friendly alternative to git.postgresql.org/gitweb, which still serves browsing but returns HTTP 429 for a=search under load (verified 2026-09-09). Unlike the /m/<inbox>.git mailing-list repos above, these endpoints index the real source repositories — the full postgres history since 1996 (65k+ commits) plus ecosystem repos (pgbouncer, pgpool2, pgjdbc, and more). Commit-message search is backed by a Postgres full-text (pg_fts) index, so it stays fast under heavy automated load.

Setup

None. Any HTTP client. All responses are JSON.

Endpoints

EndpointReturns
GET /api/v2/reposList of indexed repositories.
GET /api/v2/repos/{name}/commits?q=…Commit log / search. Params below.
GET /api/v2/repos/{name}/commits/{sha}One commit: full message, author, committer, parent. sha is a full or ≥7-char git SHA.
GET /api/v2/repos/{name}/branchesBranch list.

/commits query parameters

ParamMeaning
qFull-text search of the commit message (pg_fts, index-backed). Words are AND-ed.
authorFilter by author name or email fragment.
pathOnly commits touching this file path.
since, untilYYYY-MM-DD author-date range.
branchRestrict to a branch (served from the on-disk clone when available).
limit, offsetPage size (default 50, max 200) and offset.
Example 1: Search postgres commit messages
curl -s 'https://pg.ddx.io/api/v2/repos/postgres/commits?q=visibility+map+freeze&limit=5' | jq '.commits[] | {commit, subject, author}'

Each result has commit (the git SHA), subject, author, email, and date.

Example 2: Fetch one commit in full
curl -s 'https://pg.ddx.io/api/v2/repos/postgres/commits/deadbeef' | jq '{commit, subject, message, committer}'

A full or ≥7-char SHA prefix resolves to the commit with its complete message, committer, and parent id.

Example 3: Commits by an author in a date range
curl -s 'https://pg.ddx.io/api/v2/repos/postgres/commits?author=lane&since=2020-01-01&until=2021-01-01&limit=100' | jq '.count'

5. HTTP/REST — Programmatic Access

Purpose: Search and fetch mailing-list content with plain HTTP, no client library needed

Every indexed inbox has a search endpoint at https://pg.ddx.io/m/<inbox>/?q=<term>. Add &format=json to get JSON instead of the HTML view. Each inbox is also exposed as a public-inbox v2 git repository at https://pg.ddx.io/m/<inbox>.git.

Note: indexes are populated from upstream archives over time. If you query an inbox that's still importing you'll see “No messages yet.” or “Search is not available for this inbox.” That's import lag, not breakage. Inboxes confirmed populated today include pgsql-announce, pgsql-committers, pgsql-performance.

Setup

None. curl, wget, fetch, or any HTTP client.

Usage

The endpoint https://pg.ddx.io/m/<inbox>/?...&format=json accepts these query parameters. You may combine them; results are filtered by the intersection of the supplied predicates. At least one of q, subject, from, mid, after, or before must be present.

ParamMeaning
qFull-text query against subject, from, and body. BM25 by default; treated as a TRE regex if regex=1.
subjectFilter on the Subject header (BM25).
fromFilter on the From header (BM25; matches name or address fragments).
midExact Message-ID match (angle brackets stripped).
afterYYYY-MM-DD — only messages with Date ≥ this day.
beforeYYYY-MM-DD — only messages with Date < this day.
regex=1Interpret q as a TRE regex (uses pg_tre). URL-encode regex metacharacters.
k=NEdit-distance for fuzzy regex (0 = exact, 1+ allows that many typos). Only meaningful with regex=1; capped at 5.
format=jsonReturn JSON instead of HTML.
limit, oPage size (default 50, max 1000) and offset.
Example 1: Full-text search, JSON output
curl -s 'https://pg.ddx.io/m/pgsql-announce/?q=release&format=json' | jq '.total, .results[0]'

Returns the total hit count and the first match for “release” in pgsql-announce. Each result has subject, from, date, message_id, thread_url, message_url, and a BM25 relevance score.

Example 2: Multi-term search with paging
curl -s 'https://pg.ddx.io/m/pgsql-committers/?q=patch&format=json&limit=10&o=0' | jq '.results[].subject'

Search a different inbox; limit and o (offset) page through results. Drop &format=json to render the same query as a browseable HTML page.

Example 3: Filter by subject only
curl -s 'https://pg.ddx.io/m/pgsql-announce/?subject=release&format=json&limit=2' | jq '.total'

Restrict the BM25 match to the Subject header. Useful when the body is noisy or you only care about announcement-style headlines.

Example 4: Filter by sender
curl -s 'https://pg.ddx.io/m/pgsql-announce/?from=announce-noreply&format=json&limit=2' | jq '.results[0].from'

Match a fragment of the From header (display name or address).

Example 5: Exact Message-ID lookup
curl -s 'https://pg.ddx.io/m/pgsql-announce/?mid=177913516055.803.10890499456720421868@wrigleys.postgresql.org&format=json' | jq '.results[0].subject'

Equivalent to fetching the message page directly; convenient when you have a Message-ID from another source and want a JSON record.

Example 6: Date range
curl -s 'https://pg.ddx.io/m/pgsql-announce/?after=2024-01-01&before=2024-04-01&format=json&limit=5' | jq '.total, .results[].subject'

Q1 2024 only. after is inclusive, before is exclusive. You can combine date filters with any of the other predicates.

Example 7: Regex search
curl -s 'https://pg.ddx.io/m/pgsql-announce/?q=relea%5Bsz%5De&regex=1&format=json&limit=2' | jq '.total'

TRE regex via pg_tre. The example matches both “release” and “releaze”. Remember to URL-encode [, ], +, etc.

Example 8: Fuzzy regex (edit distance)
curl -s 'https://pg.ddx.io/m/pgsql-announce/?q=releas&regex=1&k=1&format=json&limit=2' | jq '.total'

k=1 tolerates one typo against the regex pattern; useful when subjects vary in spelling. Capped at k=5.

Example 9: Subscribe to new messages via Atom
curl -s 'https://pg.ddx.io/m/pgsql-announce/new.atom'

Standard Atom feed of recent messages. Poll no more often than once every 5 minutes — the feed only changes when new mail arrives, and aggressive polling wastes bandwidth on both sides. Most feed readers default to 30–60 minutes, which is appropriate.

Example 10: Fetch one message as raw RFC822
curl -s 'https://pg.ddx.io/m/pgsql-announce/177913516055.803.10890499456720421868@wrigleys.postgresql.org/raw'

Returns the original message bytes, including all headers and the unmodified body. URL pattern is /m/<inbox>/<message-id>/raw. Pipe into your own MIME parser or save to disk for archival.

Example 11: Bulk export a range as gzipped mbox
curl -s 'https://pg.ddx.io/m/pgsql-committers/1-100.mbox.gz' > pgsql-committers-1-100.mbox.gz zcat pgsql-committers-1-100.mbox.gz | head -20

URL pattern is /m/<inbox>/<begin>-<end>.mbox.gz, where begin and end are public-inbox v2 article numbers. Range is capped at 10000 messages per request. Use this to seed a local mbox archive without cloning the full git repo.

Example 12: Clone an inbox as a git repo
git clone https://pg.ddx.io/m/pgsql-announce.git

Public-inbox v2 layout. Run your own indexer or mirror locally for offline analysis. (Reminder: this is the mailing-list archive, not upstream PostgreSQL source.)

Tips

6. GraphQL — Structured Queries

Try it live: the GraphQL explorer runs queries against the real endpoint and has a Docs pane generated from the schema itself.

Purpose: Ask for exactly the fields you want, in one round trip

The GraphQL endpoint exposes the same data as the REST API but lets the caller specify which fields they want. Useful when you'd otherwise be making N requests in a loop and stitching JSON together.

Endpoint: POST https://pg.ddx.io/api/graphql (Content-Type: application/json). GET with a ?query=… parameter also works for read-only queries. There is no /<inbox>/graphql URL — every Query field takes an explicit inbox: String! argument instead.

Interactive explorer: open https://pg.ddx.io/api/graphql in a browser and you get the GraphiQL UI with schema introspection, autocomplete, and query history. Programmatic clients (curl, fetch with Accept: application/json) keep getting the JSON API as before.

Schema

Top-level Query fields:

Usage

Example 1: Inbox metadata + recent search results in one request
curl -s -X POST -H 'Content-Type: application/json' \ -d '{"query":"{ inbox(inbox:\"pgsql-announce\") { name messageCount lastModified } search(inbox:\"pgsql-announce\", query:\"release\", limit:3) { total results { subject date relevance } } }"}' \ https://pg.ddx.io/api/graphql

Returns both the inbox header and the first three search hits in one round trip. Compare with the REST API, which would require two calls.

Example 2: Pull a full thread by its root Message-ID
curl -s -X POST -H 'Content-Type: application/json' \ -d '{"query":"{ thread(inbox:\"pgsql-hackers\", mid:\"CABwTF4Wfs+u_O...@mail.gmail.com\") { rootMessageId messageCount messages { subject from date } } }"}' \ https://pg.ddx.io/api/graphql

Replace the mid value with a real Message-ID from the inbox you care about (you can copy one from a REST search response or the HTML view). Add body to the messages selection set if you also want the message text.

Tips

7. MCP — For AI Agents

Purpose: let an AI agent search and read the whole archive

The MCP server gives an agent the mailing lists back to the 1990s, the full postgres history, commitfest and buildfarm as tools it can call rather than pages it has to scrape. It does retrieval; your own model writes the answer, citing what the tools returned.

Endpoint

https://pg.ddx.io/mcp

MCP Streamable HTTP (JSON-RPC 2.0). No key, no account. A plain GET of that URL returns a short JSON description of the server; clients POST to it. /mcp-tools is not an endpoint — it is the human-readable reference for the tools.

Setup

Claude Code:

claude mcp add --transport http pg-ddx https://pg.ddx.io/mcp

Any client that takes a JSON config (Cursor, Zed, an Agent SDK app):

{ "mcpServers": { "pg-ddx": { "type": "http", "url": "https://pg.ddx.io/mcp" } } }

A client that only speaks the older SSE transport can use https://pg.ddx.io/mcp/sse.

A retrieval loop that works

  1. retrieve_context {"question": "...", "token_budget": 4000} — start here: cited passages that fit the budget, one per thread, or found: false when the archive does not discuss the question.
  2. hybrid_search {"query": "..."} — ranked hits, each with an excerpt of the author's own words, so you can judge a hit without opening it.
  3. get_message {"message_id": "...", "body_only": true} — one message in full.
  4. get_thread {"message_id": "...", "include_bodies": false} — an outline of the whole thread; then fetch the messages that matter. Threads are paged (20 messages per call).
  5. git_search and commit_history — from a discussion to the commit it produced, and back.

Omit inbox and it is pgsql-hackers; omit repository and it is postgres. All tools and their arguments →

Ready-made skills

Skills that teach Claude, Kiro and Pi how to use these tools well:

git clone -b claude https://codeberg.org/ddx/skills.git

Tips

WHICH SHOULD I USE?

Use Case Best Endpoint Why
Browse discussions like email IMAP Familiar email client, threading, search built-in
Download archive to computer POP3 Keep local copy, work offline
Old-school newsreader fan NNTP Classic protocol, powerful newsreaders available
Build tools / analyze history Git Version control, scripting, full history
Quick searches / dashboards HTTP/REST Simple API, JSON responses, easy integration
AI agent integration MCP Purpose-built for AI, structured queries, 100+ tools

FINDING THE BERKELEY POSTGRES HISTORICAL ARCHIVE

pg.ddx.io mirrors the University of California, Berkeley POSTGRES project (1986–1995) — the academic predecessor of PostgreSQL — at /legacy/. The upstream archive at dsf.berkeley.edu/postgres.html has been effectively static since 1999; this mirror exists so the bytes survive if the upstream ever disappears.

Mailing list (1991–1997)

The original UCB POSTGRES hackers list, including design-era discussions from Stonebraker and the original implementors:

Project documentation, papers, FAQ

The archive contains the CONCERT Trouble Ticket System (a contrib sample application), not bug tickets — UCB never used a bug tracker for the project. Patch discussions and design exchanges are in the mailing list.

Source code

TROUBLESHOOTING

IMAP won't connect

No folders appear after connecting

HTTP search returns no results

Git clone too slow

OPENAPI 3.1 SPECIFICATION

Purpose: machine-readable contract for the entire HTTP surface

Every public HTTP endpoint described on this page is also documented in a single OpenAPI 3.1 document — search, single-message JSON, raw RFC 822, threads, Atom/RSS feeds, inbox metadata, the help/color/mirror text pages, the git smart-HTTP transport, /healthz, and the MCP JSON-RPC envelope.

The spec is served by the service itself at /openapi.yaml and rendered as an interactive Swagger UI page at /api.html. Both are kept in lock-step with the service's route table.

Usage

Browse the API in your browser
https://pg.ddx.io/api

Loads Swagger UI from a CDN and points it at the live spec. Each endpoint has a “Try it out” button that issues real requests against the production service.

Fetch the raw spec
curl -s https://pg.ddx.io/openapi.yaml | head -40

Useful for embedding in your own docs site, validating with spectral lint, or generating clients with openapi-generator.

Generate a typed client
openapi-generator-cli generate -i https://pg.ddx.io/openapi.yaml -g python -o ./pgesq-client

Replace python with any of the supported targets (typescript-fetch, go, rust, etc.). The generated client speaks JSON only — for the HTML, Atom, RSS, and git smart-HTTP routes you still need a regular HTTP client.

Tips

QUESTIONS?

Something not working as described? Get in touch. We want these endpoints to work perfectly.