5b0fd61f, 2026-11-07. The text below is copied from the source byte for byte.Titlebase format specification
Version: 1.0, 2026-11-07. Reference implementation: crates/titlebase-format.
Titlebase format is the canonical format for title plant data. A Titlebase file holds one title plant: its recorded documents, its vocabulary (auto completes) and its land validations. Version 1 is a strict superset of the PropertySync plant export, so every Titlebase v1 file with its tbase_ tables removed is a valid PropertySync export, and every PropertySync export is a valid Titlebase v1 file.
The words MUST, MUST NOT, SHOULD and MAY are used as in RFC 2119.
1. Container
- A Titlebase file is a single SQLite 3 database file. Files Titlebase creates use the
.titlebaseextension. Titlebase opens.dbfiles (PropertySync exports) as they are, and exports to PropertySync as.db. - At rest, the file SHOULD use
page_size = 4096andjournal_mode = DELETE, as PropertySync writes them. - A Titlebase file MUST contain the three core tables, created with exactly these statements, in this order:
CREATE TABLE documents (id INTEGER PRIMARY KEY, data JSON);
CREATE TABLE landvalidations (id INTEGER PRIMARY KEY, data JSON);
CREATE TABLE autocompletes (id INTEGER PRIMARY KEY, data JSON);
- Core tables have no indexes, triggers or extra columns. Speed structures MUST NOT be added to core tables. They live in
tbase_tables (section 9) or in a sidecar next to the file (section 10).
2. Rows and identity
idis the SQLite rowid. It is a storage position, not an identity: the same document can have a differentidin two snapshots of a plant.- A row’s identity is the UUID in
data.id. Diffs, merges, change batches and references MUST key on it. - In PropertySync exports, document rowids are assigned in UUID order. Readers MAY use this for streaming merges but MUST NOT require it.
dataMUST be stored as TEXT in UTF-8. A NULLdatais invalid.
3. Serialization
Titlebase writes JSON exactly as PropertySync does, so an edited row is indistinguishable from a native one and an unchanged row is never touched.
| Where | Style |
|---|---|
| Outer object of every row | Compact, keys in their existing order: {"id":"…","json":{…}} |
A document’s or land validation’s inner json object, at every depth |
PostgreSQL jsonb text: object keys sorted by byte length, then by bytes; ": " after a key; ", " between members and array items; {} and [] when empty |
| Auto complete rows (flat) | Compact, keys in their existing order |
- Strings escape only
",\and control characters (\b \f \n \r \t, others as lowercase\u00XX)./is not escaped. Non-ASCII stays as UTF-8. - Numbers keep their text exactly (
20.000stays20.000). Writers MUST NOT emit exponent notation. - Writers MUST NOT rewrite a row they were not asked to change. A changed row MUST be re-emitted in the style above.
- Conformance:
tbase check roundtripparses and re-emits every row; on eight production-size reference plants (about 11.6 million documents, the largest 6.3 million documents in 16 GB) the result is 100% byte-identical.
4. Row shapes
| Shape | Form | Notes |
|---|---|---|
| Envelope | {"id":"<uuid>","json":{…}} |
Standard for documents and land validations. |
| Envelope with image | {"id":"<uuid>","imageUrl":"…","json":{…}} |
Written by Titlebase and TitleTools for new or re-imaged documents. Not present in PropertySync exports, which keep images in json.images[]. |
| Empty stub | {"id":"<uuid>","json":[]} |
Occurs in real plants (empty or removed documents). Readers MUST accept and preserve it. QC SHOULD report it. |
| Flat | {"id":"<uuid>", …fields} |
Standard for auto completes. Some third-party tools write documents flat; readers MUST accept flat documents (fields at the top level) and writers MUST keep a row’s existing shape. |
5. Documents
The inner json of a document is an object with about 60 keys, most of them often null. Readers MUST preserve every key they do not understand, byte for byte. Writers MUST NOT invent keys outside this spec or a declared legal type (section 6.3), because PropertySync rejects unknown keys.
5.1 Fields
| Group | Keys |
|---|---|
| Instrument | instrumentType, instrumentNumber, instrumentDate, filedDate (YYYY-MM-DD), filedTime, bookType, bookNumber, pageNumber, consideration, comment |
| Identifiers | indexingRecordId, recordId, recordType, caseNumber, loanNumber, uccNumber, orderOfCourt, filmNumber, microFilmNumber |
| Status | status, flags, company, checkedOutBy, marketSource, userField1 to userField5, otherFields |
| Addresses | property{StreetNumber, StreetName, StreetType, StreetDirection, UnitType, UnitNumber, City, State, Zip}, return{…}, address[] |
| Parties | grantors[], grantees[], otherParties[] |
| Legal | subdivisionLegal[], acreageLegal[], abstractLegal[], originalLegal (section 6) |
| Links and media | related[], images[], imageId, tags[], parcelNumbers[] |
- Mixed scalar types are valid and MUST round-trip:
consideration(string, integer or decimal),indexingRecordIdandimageId(string or integer),abstractNumber(string or integer),block(range array or scalar).
5.2 Parties
{"nameLast", "nameFirst", "nameMiddle", "nameType"}; nameType is "I" (individual), "O" (organization) or null. Some plants store the full name in nameLast with the other parts null. otherParties[] items MAY add role and nameSuffix.
5.3 Related documents, images, tags
related[]:{"instrumentNumber", "instrumentType", "bookType", "bookNumber", "pageNumber"}. Duplicates and number-only entries occur.images[]:{"path" (an s3:// URL), "fileType", "pageNumFrom", "pageNumTo", "imageId", "fileName", "fileSize", "serverVolume", "statusFlags", "namingConvention", …}.tags[]: strings.
6. Legal descriptions
6.1 Arrays and the wide row
Legal descriptions are stored in three arrays on the document. All three share one wide row shape: landType, landFlags, addition, subdivision, survey, section, township, range, quarters, abstractNumber, abstractName, lot[], block[], unit[], acres[], arb[], parcel, pid, comment, recDate, bookType, bookNumber, pageNumber, action, previousArb, previousParcel. Plants MAY carry additional keys.
6.2 Titlebase standard legal types
Titlebase names legal descriptions by industry-standard type. PropertySync’s per-plant part names are not part of this spec. Each standard type maps to an array and a set of keys:
| Standard type | Array | Key fields |
|---|---|---|
| Subdivision | subdivisionLegal |
addition, lot[], block[], unit[], plat bookType / bookNumber / pageNumber |
| Unit / condominium | subdivisionLegal |
addition, unit[], block[] |
| Tract | subdivisionLegal |
addition, tract ranges |
| PLSS (section, township, range) | acreageLegal |
section, township (4N), range (1E), quarters (SWSW), acres[] |
| Government lot | acreageLegal |
section, township, range, government lot ranges |
| Acreage | acreageLegal |
acres[], subdivision or addition when a plant records a named tract here |
| Abstract (Texas survey) | abstractLegal |
survey, abstractNumber, section, block[], acres[] |
| Parcel | any | parcel, pid, arb[] |
| Free text | document | originalLegal |
Plants differ in where they place some legal keys (for example a plat name recorded in acreageLegal). Readers MUST accept any of these placements.
6.3 Custom legal types
A user MAY define a legal type that extends a standard type with extra keys. Custom types are kept in the user’s local library. A future version MAY store them in the file as tbase_legal_types (section 9). Custom keys appear in the legal row like any other key and are preserved by every reader.
6.4 Range values
lot, block, unit, acres and arb are arrays of range objects:
{"rangeMax": "3", "rangeMin": "1", "rangeAction": null, "rangePrecision": null}
rangeMinandrangeMaxare strings; a single value has min equal to max.rangeAction,rangePrecision,landType,landFlagsand the rowactionare pass-through fields. No authoritative meaning is documented for them. Writers MUST preserve them exactly and MUST NOT normalize them.- Key-case and key-set variants exist in real plants (
rangemin, ranges without action or precision) and MUST round-trip.
7. Auto completes
Flat rows: {"id":"<uuid>","type":"…","value":"…"}. Known type values: addition, bookType, instrumentType, survey, marketSource, party. Others MAY occur. Auto complete rowids are not in UUID order.
8. Land validations
Envelope rows: {"id":"<uuid>","json":{"addition": "…", "platValidation": [ … ]}}, inner json in jsonb style.
- Header keys MAY include
platDate,bookNumber,pageNumber. - Each
platValidationentry MAY includestatus,landType,lot[],block[],unit[],landValDate,vacateDate,commentand other keys. statusplat codes:"0"plat,"1"replat,"2"vacate,"3"comment only. Some plants carry higher bits instatus; preserve them.- Land validation rows carry no type tag; the legal type is inferred from the keys present.
9. Titlebase extension tables
- Tables whose names start with
tbase_are reserved for this spec. Readers MUST ignoretbase_tables they do not know. - Exporting to PropertySync format MUST drop every
tbase_table. - Defined in v1:
CREATE TABLE tbase_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);
Keys: format_version (1.0), created_by (tool and version), created_at, source (where the plant came from, for example a PropertySync document group or an importer name). A file without tbase_meta is a Titlebase v1 file with unknown provenance.
- Reserved for later versions:
tbase_legal_types(custom legal types),tbase_journal(change history), speed structures.
10. Sidecar
Search indexes, the edit journal and caches live in a folder next to the file, <file>.tbase/, never inside it. The sidecar is derived data: deleting it loses nothing that Save has not written.
11. Importers and exporters
Other title plant formats enter and leave through importers and exporters. An importer MUST produce a file that meets this spec. An exporter to PropertySync MUST produce the core tables only. Each importer and exporter documents its field mapping next to its code.
12. Versioning
MAJOR.MINOR. A minor version adds optionaltbase_tables or optional keys; v1 readers can read any 1.x file. A major version may change core rules.- Changes to this spec go through the repo’s normal review, with a line in this file’s history.
History
- 1.0, 2026-11-07: first published version.