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.
DDX for PostgreSQL offers multiple protocols to access the same data. Choose the one that fits your workflow:
POST /api/graphql — one round trip, multi-inbox queries via aliasingIMAP 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.
pgsql-general (most active, general discussion).
1. Click "pgsql-hackers" folder
2. Your email client shows the newest messages first
3. Click a message to read the full thread
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
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
POP3 downloads messages and removes them from the server. Use this if you want to keep a local archive of PostgreSQL discussions.
Username format is required and strict. The server replies
-ERR no UUID@ in mailbox name if the <UUID>@
prefix is missing.
deadbeefdeadbeefdeadbeefdeadbeef or
dead-beef-dead-beef-dead-beef-dead-beef.pgsql.hackers,
pgsql.general, pgsql.bugs.anonymous.Example username: deadbeefdeadbeefdeadbeefdeadbeef@pgsql.hackers
Set your client to check every 24 hours. All new messages download and stay on your computer. Good for backup and offline research.
If you use a newsreader (Thunderbird, Usenet clients), connect via NNTP. Each mailing list appears as a newsgroup.
In Thunderbird, tick Use secure connection (SSL) and set the port to 563. No username or password is needed.
Note: Newsgroup names use hyphens, not dots.
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.
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.
(Shows how many messages per day)
git clone --depth 100 https://pg.ddx.io/m/pgsql-hackers.gitReplace pgsql-hackers with any list on the archive.
The message feeds hold the 25 newest messages; the two topic feeds hold 50 threads.
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.
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.
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:
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.
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.
None. Any HTTP client. All responses are JSON.
| Endpoint | Returns |
|---|---|
GET /api/v2/repos | List 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}/branches | Branch list. |
/commits query parameters| Param | Meaning |
|---|---|
q | Full-text search of the commit message (pg_fts, index-backed). Words are AND-ed. |
author | Filter by author name or email fragment. |
path | Only commits touching this file path. |
since, until | YYYY-MM-DD author-date range. |
branch | Restrict to a branch (served from the on-disk clone when available). |
limit, offset | Page size (default 50, max 200) and offset. |
Each result has commit (the git SHA), subject, author, email, and date.
A full or ≥7-char SHA prefix resolves to the commit with its complete message, committer, and parent id.
The /search page searches the mailing lists and the git commit history together, and every search is a deep link (the query lives in the URL: /search?q=…&l=<list>&repo=<repo>&src=mail|git|both). Pick which sources and which list/repo to search with the checkboxes and facets; results are clickable (mail → the message; commit → the gitweb-style commit view).
In the search box you can use these lore-style prefixes (also available as URL params on the JSON APIs):
| In the box | Means |
|---|---|
s:pruning | match the subject |
f:lane | match the sender (name/address) |
"visibility map" | exact phrase |
| plain words | full-text (all words must appear) |
Machine access: mail → GET /api/v2/mail/search?q=&list= (omit list for all lists); git → GET /api/v2/repos/{repo}/commits?q= or the short GET /c/?q= (defaults to postgres) / GET /c/{repo}/?q=. All return JSON with links (message_url/thread_url for mail, commit SHA for git).
Mail ranking (mode= on the mail API, “Match by” on the page): hybrid (default) blends the keyword score with meaning (embedding similarity) per thread, so a question in your own words finds a discussion that used different ones; keyword ranks by the words alone (best for exact identifiers such as function or setting names); semantic ranks by meaning alone. Mail results come one per thread unless all=1.
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.
None. curl, wget, fetch, or any HTTP client.
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.
| Param | Meaning |
|---|---|
q | Full-text query against subject, from, and body. BM25 by default; treated as a TRE regex if regex=1. |
subject | Filter on the Subject header (BM25). |
from | Filter on the From header (BM25; matches name or address fragments). |
mid | Exact Message-ID match (angle brackets stripped). |
after | YYYY-MM-DD — only messages with Date ≥ this day. |
before | YYYY-MM-DD — only messages with Date < this day. |
regex=1 | Interpret q as a TRE regex (uses pg_tre). URL-encode regex metacharacters. |
k=N | Edit-distance for fuzzy regex (0 = exact, 1+ allows that many typos). Only meaningful with regex=1; capped at 5. |
format=json | Return JSON instead of HTML. |
limit, o | Page size (default 50, max 1000) and offset. |
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.
Search a different inbox; limit and o (offset) page through results. Drop &format=json to render the same query as a browseable HTML page.
Restrict the BM25 match to the Subject header. Useful when the body is noisy or you only care about announcement-style headlines.
Match a fragment of the From header (display name or address).
Equivalent to fetching the message page directly; convenient when you have a Message-ID from another source and want a JSON record.
Q1 2024 only. after is inclusive, before is exclusive. You can combine date filters with any of the other predicates.
TRE regex via pg_tre. The example matches both “release” and “releaze”. Remember to URL-encode [, ], +, etc.
k=1 tolerates one typo against the regex pattern; useful when subjects vary in spelling. Capped at k=5.
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.
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.
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.
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.)
&format=json.?limit=N&offset=M. Default limit is 50, max 1000 (server-enforced).https://pg.ddx.io/ in a browser to see the full inbox list and pick one.Try it live: the GraphQL explorer runs queries against the real endpoint and has a Docs pane generated from the schema itself.
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.
Top-level Query fields:
inbox(inbox: String!) — metadata: name, description, addresses, message count, last-modified.messages(inbox: String!, limit: Int = 25) — recent messages.message(inbox: String!, mid: String!) — one message by Message-ID, including body and attachments.thread(inbox: String!, mid: String!) — full thread rooted at a Message-ID.search(inbox: String!, query: String!, limit: Int = 50, offset: Int = 0) — BM25 search; results carry a relevance score.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.
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.
errors array. Check both data and errors in your client.inbox argument is required on every field. The endpoint is not scoped to any inbox; the schema deliberately surfaces the inbox name in each query so a single GraphQL request can span multiple inboxes by aliasing.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.
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.
Claude Code:
Any client that takes a JSON config (Cursor, Zed, an Agent SDK app):
A client that only speaks the older SSE transport can use
https://pg.ddx.io/mcp/sse.
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.hybrid_search {"query": "..."} — ranked hits, each with an
excerpt of the author's own words, so you can judge a hit without
opening it.get_message {"message_id": "...", "body_only": true} — one
message in full.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).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 →
Skills that teach Claude, Kiro and Pi how to use these tools well:
HTTP 429; back off and retry.| 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 |
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.
The original UCB POSTGRES hackers list, including design-era discussions from Stonebraker and the original implementors:
/m/legacy//m/legacy/?q=stonebraker/m/legacy/new.atom/legacy/mail-archive/ (64 monthly tarballs plus a single aggregated all-messages.mbox for grep)search_messages(inbox="legacy", query="vacuum")/legacy/papers/ — both PostScript and ps2ascii text. Includes "Design of POSTGRES", "Implementation of POSTGRES", "Rules, Procedures and Caching", and ten more./legacy/postgres-v4r2/postgres.faq/legacy/postgres-v4r2//legacy/postgres-v4r2/contrib/sha256: /legacy/manifest.json/legacy/upstream-snapshot.htmlThe 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.
/legacy/extracted/ or grab the tarball /legacy/postgres-v4r2/postgres-v4r2.tar.Z./legacy/oldpost//legacy/oldpost/unofficial-ports/, UNOFFICIAL-PORT-LIST.search_symbols(repository="ucb-postgres-v4r2", query="parser") and git_log(repository="ucb-postgres-v4r2"). The expected repository names are ucb-postgres-{v3r1,v4r0,v4r1,v4r2} and ucb-postgres95-{0.01..1.02}; consult /data for current indexing status.imap.pg.ddx.io (no www, no .com)pgsql-general?q=query instead of complex syntax+ or %20jq . to see response structuregit clone --depth 10 ...git log -p --max-count=100Every 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.
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.
Useful for embedding in your own docs site, validating with spectral lint, or generating clients with openapi-generator.
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.
&format=json for the JSON envelope. The OpenAPI document only describes the JSON variant.Link headers (RFC 8288 rel="next" / rel="prev" / rel="first") instead of recomputing offsets. The body's has_more is also reliable.POST /mcp/ entry in the spec describes the JSON-RPC envelope. AI agents should use a real MCP client library; the OpenAPI is there mostly for debugging.Something not working as described? Get in touch. We want these endpoints to work perfectly.