---
title: "SPDF: documents read once, cited forever"
description: "SPDF is an open file format for documents that have already been read. Every passage carries its exact anchor (printed page, folio, second, slide, verse), so a citation can only print what the source says."
url: https://spdf.joseluissaorin.com/
markdown: https://spdf.joseluissaorin.com/index.md
lang: en
alternate_es: https://spdf.joseluissaorin.com/es.md
updated: 2026-10-07
author: José Luis Saorín Ferrer (https://joseluissaorin.com)
license: CC-BY-4.0
---

# SPDF: documents read once, cited forever

> SPDF is an open file format for documents that have already been read. Every passage carries its exact anchor (printed page, folio, second, slide, verse), so a citation can only print what the source says.

[Read the specification](https://spdf.joseluissaorin.com/spec.md) · [Validate a file](https://spdf.joseluissaorin.com/validator.md) · [Open the reader](https://spdf.joseluissaorin.com/reader/)

Anchor URI: `spdf:sha256-a156ce5ac9858e29e74bdc90c424fa1b77621bde7204d43faf18c2e726243ab0#p=41&f=17r&char=0,1424` → (Galilei, 1610, fol. 17r)

Physical page 41 of the file, printed folio 17r, characters 0 to 1424 of that page, in *Sidereus nuncius*. The citation is computed from the anchor stored at reading time; nothing is guessed. [Open it in the validator](https://spdf.joseluissaorin.com/validator#url=/commons/files/galilei-sidereus-nuncius-1610.spdf).

## Why a format

Reading a document well is slow and expensive: OCR, transcription, finding the printed folios, sectioning, embeddings. SPDF stores the result so that nobody has to do it twice, and so that whatever cites from it can be checked.

### I. Anchors

Every passage knows where it is. Fragments are stored with the place they came from: physical page and printed folio (roman, inferred or by leaf), second and word timings in audio and video, slide, sheet range, verse line or a canonical reference such as Stephanus 514a. Anchors serialise as portable URIs.

`{"type":"page","physical":29,"printed":"21"}`

### II. Provenance

Every field says who wrote it. Each unit records which reader produced its text (a PDF text layer, a vision model, a speech recogniser) and with what confidence; the metadata records where each field came from (colophon, title page, catalogue). Inferred folios are cited in brackets.

`reader: gemma-4-e4b · confidence: 0.97`

### III. Read once, query many

The expensive part happens once. OCR, transcription, sectioning and embeddings are paid for when the file is produced. After that it answers lexical, semantic and hybrid queries offline, even on a phone, with SQLite’s own full-text index and vectors from several models side by side.

`fts5 unicode61 · f32 | f16 | i8 · RRF k = 10`

### IV. Portability

One file, any language, no server. A .spdf is a plain SQLite 3 database: no custom container, no account. It can be memory-mapped or read over HTTP ranges, and twelve independent implementations open it, all tested against the same conformance suite.

`one document = one file`

### V. Honest citation

A citation can only print what the source says. Short citations and bibliography (CSL-JSON, BibTeX) are derived from the stored anchor and the CSL record, never generated. Agents get the same guarantee through the MCP server: they search, they quote and they cite with the exact folio, and they cannot invent one.

`(Saorín Ferrer, 2026, p. [3])`

## Inside a .spdf

A single SQLite file, uncompressed so it can be read by ranges, with no triggers and no views. Readers open it read-only, in defensive mode, and never load extensions. The schema is small enough to learn in an afternoon.

| Table | What it holds |
| --- | --- |
| `spdf_meta` | version, profile, generator, document id |
| `documents` | one CSL-JSON record, with the provenance of each field |
| `units` | the citable units: pages, time spans, slides, sheets |
| `fragments` | passages of 150 to 300 words with their anchors |
| `fragments_fts` | FTS5 index, accent-insensitive |
| `sections` | the heading tree |
| `figures` | figures, plates and frames, with region and description |
| `spaces` | vector spaces, declared as model@dims |
| `vectors` | little-endian f32, f16 or i8 |
| `blobs` | the original and the images, with their SHA-256 |
| `provenance` | what produced what, with which model, and when |
| `extensions` | x_vendor_name tables, required or optional |

### Profiles

- `core`: Text and anchors. Enough to search and cite.
- `semantic`: Core plus vectors from one or more embedding models.
- `media`: Core plus audio and video with per-word timings.
- `full`: All of the above.

## Twelve implementations, one suite

The Rust implementation is the reference and also exposes a C ABI. The others are native and independent: each one opens, validates, dumps, searches, formats anchors, cites and writes, and each one is checked by the same conformance cases on every commit.

- **Rust** (`spdf`): CI running. https://spdf.joseluissaorin.com/docs/rust.md
- **TypeScript** (`spdf-format`): CI running. https://spdf.joseluissaorin.com/docs/js.md
- **Python** (`spdf-format`): CI running. https://spdf.joseluissaorin.com/docs/python.md
- **Swift** (`SPDF`): CI running. https://spdf.joseluissaorin.com/docs/swift.md
- **Kotlin / JVM** (`io.github.joseluissaorin:spdf`): CI running. https://spdf.joseluissaorin.com/docs/kotlin.md
- **Go** (`github.com/joseluissaorin/spdf/go`): CI running. https://spdf.joseluissaorin.com/docs/go.md
- **C# / .NET** (`Spdf.Format`): CI failing. https://spdf.joseluissaorin.com/docs/dotnet.md
- **PHP** (`joseluissaorin/spdf`): CI running. https://spdf.joseluissaorin.com/docs/php.md
- **Ruby** (`spdf-format`): CI running. https://spdf.joseluissaorin.com/docs/ruby.md
- **R** (`spdf`): CI running. https://spdf.joseluissaorin.com/docs/r.md
- **Julia** (`SPDF.jl`): CI running. https://spdf.joseluissaorin.com/docs/julia.md
- **C** (`libspdf`): CI running. https://spdf.joseluissaorin.com/docs/c.md

## Where to start

### Validate

Drop a .spdf on the validator: it checks the file against the specification and shows what is inside, in your browser, without uploading anything.

https://spdf.joseluissaorin.com/validator.md

### Read

SPDF Reader opens, searches and cites SPDF files on macOS, Windows, Linux, iOS, Android and the web, with local models and no account.

https://spdf.joseluissaorin.com/download.md

### Build

spdf build turns a PDF, a scan, an EPUB or a recording into an SPDF with local models, or with your own API key. Or start from SPDF Commons, a small collection of public-domain works.

https://spdf.joseluissaorin.com/commons.md

### For agents

Every page of this site has a Markdown twin (the same address ending in .md), /llms.txt indexes them and /llms-full.txt carries the whole specification. The spdf-mcp server lets any agent search a folder of SPDF files and cite with the exact folio.

https://spdf.joseluissaorin.com/agents.md
