developer resources

.inkbook file specification

version 1 format schema & integration guidelines

The .inkbook format is a light, local-first JSON document schema designed to persist drawing notebooks written on Cecilia's Notes iPad application. Because notebooks are stored as plain files, external LLM agents, scripts, and MCP servers can safely read, append, and replace notebooks to integrate note-taking into code-generation or productivity workflows.

machine-readable contracts

Use these resources to programmatically validate document structure.

mcp server integration

To make it easy for AI agents and LLMs to interact with the notes application, we have published the official Model Context Protocol (MCP) server for Cecilia's Notes. External agents can use this MCP server to read, query, and modify notebooks programmatically using standard tools.

Users can install the MCP server globally via npm:

npm install -g cecilias-notes-mcp

Once installed, add it to your local MCP client configuration (such as Claude Desktop or Cursor) to grant your AI assistants direct access to interact with your local notebook library.

Top-Level Schema

An .inkbook file is a single JSON object with version "1" metadata. The tables below map the required fields and constraints.

Field Type Required Notes & Context
$schema string (uri) optional Must match exactly https://venugopinath.me/cecilias-notes/schemas/inkbook/v1.json
version string required Fixed value "1" for this specification version.
id string (uuid) required Unique UUID for the notebook. Casing rules apply (see below). Filename format must be <id>.inkbook.
title string required The title displayed at the top of the iPad notebook workspace.
subject string required A free-form category/folder tag. If the subject does not exist on import, the iPad app automatically creates it.
created_at string (timestamp) required ISO-8601 UTC timestamp with second precision (e.g. YYYY-MM-DDTHH:MM:SSZ).
updated_at string (timestamp) required ISO-8601 UTC timestamp with second precision (e.g. YYYY-MM-DDTHH:MM:SSZ).
cover_tone string enum optional Cover tone visual. Must be one of: parchment, studio-white, ash, coal, midnight, moss, dusk, ink-black.
page_template string enum optional Background grid layout. Must be one of: blank, lined, grid, dot-grid, cornell, music.
page_size string enum optional Aspect ratio constraints. Must be one of: a4, letter, ipad-canvas.
agent object optional Metadata identifying the writing system (see sub-schemas below).
pages array required List of page objects containing the note content.
mcp_action string enum optional V1.1+ field for optimistic concurrency. One of: create, append, replace.
base_updated_at string (timestamp) optional The last updated_at value read prior to editing. Required when mcp_action is set to "append".
UUID Casing Rule
Writers SHOULD emit the id field using **uppercase** strings to align with iOS native UUID().uuidString behavior. However, readers MUST parse and compare UUID values using **case-insensitive** matching.

Agent Metadata Object

Writers utilize the agent object to leave an audit trail, indicating which client-side wrapper, LLM model, or tool interface modified the file.

{
  "written_by": "cecilias-notes-mcp", // e.g., name of the adapter
  "model": "gemini-3.5-flash",       // optional: model signature
  "tool": "append_page",             // name of tool action
  "tool_version": "1.0.4"            // tool version
}

Page Structure

Each entry in the pages[] array holds the following fields:

Content Block Union (Discriminated)

Content within a page is structured as a list of components called blocks. Each block contains a type string parameter that acts as a discriminator.

Extensibility Policy
To ensure forward compatibility, unknown block types **must** be tolerated by readers. If an app encounters a block type it does not recognize, it must gracefully skip that block instead of throwing a parsing error.

The v1 format supports the following block shapes:

Block Type Properties Example JSON Representation
heading content (string)
level (int: 1, 2, or 3)
{
  "type": "heading",
  "content": "Section Title",
  "level": 2
}
paragraph content (string)
{
  "type": "paragraph",
  "content": "Standard note content goes here."
}
list style (string: "bullet" | "numbered")
items (array of strings)
{
  "type": "list",
  "style": "bullet",
  "items": ["First item", "Second item"]
}
code content (string)
language (optional, string)
{
  "type": "code",
  "content": "print('hello')",
  "language": "python"
}
divider None
{
  "type": "divider"
}
quote content (string)
attribution (optional, string)
{
  "type": "quote",
  "content": "To be or not to be.",
  "attribution": "Shakespeare"
}
callout content (string)
kind (string: "note" | "warning" | "tip")
{
  "type": "callout",
  "content": "Remember to save.",
  "kind": "note"
}

Optimistic Concurrency Contract

Since notebooks sync via files in iCloud Drive, multiple actors (the iPad App, desktop scripts, AI agents) might try to write to a file at the same time. To prevent concurrent edits from overwriting each other and causing data loss, Cecilia's Notes employs an optimistic concurrency contract using the mcp_action and base_updated_at parameters.

A writer performing a read-modify-write action (such as appending a page or changing content blocks) **must** follow this lifecycle:

  1. **Read**: Load the current .inkbook file from storage.
  2. **Stash**: Record its updated_at timestamp value as your target base_updated_at.
  3. **Mutate**: Apply the desired modifications, and generate a new updated_at timestamp corresponding to the present time.
  4. **Write**: Write back the file, setting mcp_action to "append" and base_updated_at to the stashed timestamp.

When Cecilia's Notes iPad App receives a write request, it applies the following evaluation matrix:

Situation Action Applied Reasoning
No existing notebook is registered with this notebook's id. Wholesale Replace Treated as a clean, initial notebook creation.
The mcp_action parameter is missing, or set to "create", "replace", or an unrecognized value. Wholesale Replace Force overwrite. Either the notebook is new, or the writer explicitly requested to override history (e.g. "replace").
mcp_action is "append" and the notebook's current updated_at equals the incoming base_updated_at. Wholesale Replace **Safe operation**. No concurrent changes occurred since the writer read the file; history is updated cleanly.
mcp_action is "append" and the notebook's current updated_at does NOT equal the incoming base_updated_at. Merge **Conflict detected**. Concurrent edits occurred. The app retains all existing pages, and only appends new pages from the write payload whose page id does not conflict with existing pages.
mcp_action is "append", but the base_updated_at value is missing. Merge **Conservative fallback**. Since concurrency state cannot be proven, the app merges to safeguard against page data loss.
Strict Overwrite
If an external agent wishes to enforce a full, absolute replacement of the notebook regardless of its concurrent modification state, it must send mcp_action: "replace".