Guntosha

shelff JSON Specification

shelff stores metadata and reading progress for PDF files as JSON files in iCloud. This page describes the specification of the JSON files that shelff reads and writes.

shelff manages its data through these JSON files. Other tools can interoperate with shelff by reading and writing the same files.

Overview

shelff uses three types of JSON files.

File Location Purpose
*.pdf.meta.json Same directory as the PDF Per-PDF metadata, reading progress, and display settings
.shelff/categories.json .shelff directory under the shelff document root Category definitions and ordering
.shelff/tags.json .shelff directory under the shelff document root Tag display order

The metadata file (*.pdf.meta.json) is automatically created when a PDF is first opened in shelff. At that point, dc:title is set to the filename.

All files use UTF-8 encoding. Dates are recorded in ISO 8601 format.

Metadata File *.pdf.meta.json

A metadata file corresponds to a single PDF file. It is stored in the same directory as the PDF, with .meta.json appended to the original filename.

Example: my-book.pdf → my-book.pdf.meta.json

Example

{
  "schemaVersion": 1,
  "metadata": {
    "dc:title": "Introduction to Programming",
    "dc:creator": ["Jane Smith"],
    "dc:publisher": "Tech Press",
    "dc:date": "2024",
    "dc:language": "en",
    "dc:subject": ["Programming", "Introduction"],
    "dc:identifier": "978-0-00-000000-0"
  },
  "reading": {
    "lastReadPage": 42,
    "totalPages": 300,
    "lastReadAt": "2025-03-20T14:30:00Z",
    "status": "reading",
    "finishedAt": null
  },
  "display": {
    "direction": "LTR",
    "pageLayout": "spread-with-cover",
    "crop": {
      "excludeFirstPage": true,
      "odd":  { "top": 0.05, "bottom": 0.04, "left": 0.03, "right": 0.03 },
      "even": { "top": 0.05, "bottom": 0.04, "left": 0.02, "right": 0.04 }
    }
  },
  "collection": { "title": "Introduction to Programming Series", "position": 1 },
  "category": "Technical",
  "tags": ["Swift", "Beginner"],
  "bookmarks": [
    { "page": 3, "label": "Important diagram" },
    { "page": 15 },
    { "page": 42 }
  ]
}

Top-level Fields

Field Type Required Description
schemaVersion Integer Yes Schema version. Currently 1
metadata Object Yes Bibliographic metadata (see below)
reading Object No Reading progress (see below)
display Object No Display settings (see below)
collection Object No The collection (series or magazine) this book belongs to. At most one per PDF
category String No Category name (one per PDF)
tags Array of strings No Tag names
bookmarks Array of objects No User-defined page bookmarks (see below)

metadata Object

Bibliographic metadata. Field names use dc:-prefixed keys based on Dublin Core Metadata Terms.

Field Type Required Description
dc:title String Yes Title
dc:creator Array of strings No Author(s)
dc:date String No Date. "2024", "2024-06", and "2024-06-15" are all valid
dc:publisher String No Publisher
dc:language String No Language code (e.g., "ja", "en")
dc:subject Array of strings No Subjects / keywords
dc:identifier String No Identifier (e.g., ISBN)

reading Object

Field Type Required Description
lastReadPage Integer Yes Last read page number (1-based)
totalPages Integer Yes Total number of pages
lastReadAt String Yes Last read timestamp (ISO 8601)
status String No Reading status: "unread" / "reading" / "finished"
finishedAt String No Completion timestamp (ISO 8601)

display Object

Field Type Required Description
direction String Yes Reading direction: "LTR" (left-to-right) / "RTL" (right-to-left)
pageLayout String No Page layout: "single" / "spread" / "spread-with-cover"
crop Object or null No Margin crop (see below). Absent or null means no crop

display.crop Object

A non-destructive margin crop applied when rendering pages. The PDF file is never modified; readers apply the crop to the displayed page bounds.

Field Type Required Description
odd Object Yes Insets for odd-numbered pages (1, 3, 5, …) (see below)
even Object Yes Insets for even-numbered pages (2, 4, 6, …) (see below)
excludeFirstPage Boolean No When true, page 1 (typically the cover) is displayed uncropped. Defaults to false

Parity is determined by the PDF page number (1-based) and is independent of pageLayout and direction. For a uniform crop, write the same values to both odd and even.

odd / even are objects with the following four fields. Values are ratios (0.0–1.0) of the page's MediaBox, expressed in the page's displayed orientation (after /Rotate is applied).

Field Type Required Description
top Number Yes Inset from the top edge, as a ratio of the page height
bottom Number Yes Inset from the bottom edge, as a ratio of the page height
left Number Yes Inset from the left edge, as a ratio of the page width
right Number Yes Inset from the right edge, as a ratio of the page width

Each value must be >= 0, with top + bottom < 1 and left + right < 1. Readers treat a crop that violates these constraints as absent rather than failing. Tools that rewrite display must preserve crop.

bookmarks Array

An array of user-defined page bookmarks (digital "sticky notes"). These are distinct from the PDF's built-in document outline; readers add them to mark pages of interest.

Field Type Required Description
page Integer Yes Bookmarked page number (1-based)
label String No Bookmark label. When omitted, readers may fall back to the page number

collection Object

An object representing the series or magazine a PDF belongs to. Inspired by EPUB's belongs-to-collection / group-position, simplified to a single collection without a type distinction.

Field Type Required Description
title String Yes Name of the collection or series
position Number No Position within the collection. Fractional values allowed (e.g. 0.5 for a special half-volume). Omit for collections ordered by other means such as magazine publication date

Categories File categories.json

Stored in the .shelff directory under the shelff document root, this file defines the available categories. Each PDF can belong to at most one category.

Example

{
  "version": 1,
  "categories": [
    { "name": "Technical", "order": 0 },
    { "name": "Fiction", "order": 1 },
    { "name": "Papers", "order": 2 }
  ]
}
Field Type Description
version Integer Schema version. Currently 1
categories Array Array of categories. Each element has name (string) and order (integer, 0-based)

Tags File tags.json

Stored in the .shelff directory under the shelff document root, this file defines the display order of tags. Tags themselves are defined in the tags field of each PDF's metadata file. This file only manages display ordering.

Example

{
  "version": 1,
  "tagOrder": ["Swift", "SwiftUI", "Programming", "To Read"]
}
Field Type Description
version Integer Schema version. Currently 1
tagOrder Array of strings Tag display order. Tags not in this array are appended in name order

Extension Fields

All three files allow additional top-level fields. Third-party tools and users storing custom data should use the x- prefix (e.g. x-calibre-id). The same applies inside the metadata object, where standard Dublin Core extensions such as dcterms: are also welcome. The reading and display objects do not allow additional fields.

Any tool that reads and writes these files, shelff included, must preserve fields it does not understand and write them back unchanged.

JSON Schema

Formal JSON Schema definitions for each file format are available in the following repository.