Skip to content

Logbook format — specification v0.1

Status: draft. License: CC0. Anyone may implement this without asking.

The key words MUST, MUST NOT, SHOULD and MAY are to be interpreted as described in RFC 2119.

1. The folder

<root>/
  logbook.json            identity and chain head
  logbook/<YYYY>/<MM>.jsonl   the record
  notes/<YYYY>/<YYYY-MM-DD>.md   free text, optional
  inbox/                  optional; not part of conformance

logbook.json:

{"format": "logbook/0.1", "owner_id": "<uuid>", "created_at": "<RFC3339 UTC>",
 "timezone": "<IANA tz>", "seq": 4181, "head": "<hex sha256>"}

2. The line (the envelope)

One observation per line, JSON, UTF-8, newline-terminated, in logbook/<YYYY>/<MM>.jsonl, where YYYY and MM are taken from at in UTC.

Field Type Meaning
id uuid UUIDv7 (RFC 9562) recommended; identity of this line; outside the hash so it may be assigned at write time
seq integer ≥ 1 position in the owner's chain; strictly increasing by 1
at RFC3339 UTC when the thing happened (not when it was recorded)
end RFC3339 UTC or null when it stopped, if it had a duration
tz IANA name the owner's timezone at at
source string who reported it: manual, apple-health, google-takeout, …
kind string what it is: location, photo, event, message, sleep, note, …
tier 1, 2 or 3 privacy tier, §4
payload object whatever the source said; MUST contain schema, e.g. "location/v1"
recorded_at RFC3339 UTC when the line was written
prev hex sha256 hash of the previous line; 64 zeros for the first
hash hex sha256 §3

Unknown fields MUST be preserved by readers and MUST NOT be added by writers at the top level; extensions go inside payload.

3. The chain

content = canonical_json({at, end, tz, source, kind, tier, payload})
hash    = sha256( prev + "|" + seq + "|" + sha256(content) + "|" + recorded_at )

canonical_json is RFC 8785 (JSON Canonicalization Scheme): keys sorted by UTF-16 code units, no whitespace, UTF-8, ES6 number serialisation, no NaN/Infinity. A logbook is valid when, taking every line from every file and ordering by seq (files partition by the month of at, so backfilled history lands in old files; file order is not chain order), every line's seq is the previous plus one, every prev equals the previous hash, every hash recomputes, and logbook.json seq/head match the last line.

Corrections are new lines. A source that revises an earlier record writes a new line with payload.supersedes = "<id>". Nothing is ever rewritten or removed.

4. Tiers

Tier Typical content At rest
1 location, photo metadata, calendar, public activity plain
2 notes, messages, decisions, confirmations, personal mail encrypted with the owner's key (v0.2)
3 money, health encrypted with the owner's key (v0.2)

Derived data inherits the highest tier of its evidence. v0.1 conformance requires the field; v0.2 will define the encryption envelope for tiers 2–3 (payload_enc replacing payload, age/X25519 recipient = the owner's key).

5. Payload profiles

The envelope is the standard. Payloads are versioned by payload.schema and proposed as RFCs in rfcs/. Seed profiles: location/v1, photo/v1, event/v1, message/v1, transaction/v1, health-sample/v1, note/v1. A logbook with unknown schemas is still valid.

6. Conformance

An implementation is conformant when verify on conformance/sample-logbook reports valid and prints the head in conformance/expected.json, and when appending one line to a copy of it yields a logbook that still verifies. Level 2 conformance (v0.2) adds encryption. Two independent implementations must agree before v1.0 is frozen.

7. What this spec does not say

Nothing about servers, databases, user interfaces, engines, agents, or how two logbooks exchange pages. Those are layers. The spec is finished when it is small enough to implement in an afternoon.