This page covers how .showpapers files move between the ShowPapers apps and AI apps:
- what a file is called and which types it carries;
- how a receiver recognizes it;
- an optional plain JSON companion for AI apps that cannot open ZIP files;
- what an AI app hands back.
The archive rules are in Collection Format. A sender shares the .showpapers file directly. The optional JSON companion describes its contents for a reader that cannot open an archive; it is not the collection itself.
Names And Types
| Use | Name | Media type | Apple UTI |
|---|---|---|---|
| Canonical file (saving, sharing with a person, opening, and handing to an AI app) | <name>.showpapers | application/vnd.showpapers.collection | app.showpapers.collection, conforming to public.data and public.content |
| Accepted alias on read | — | application/vnd.showpapers.collection+zip | — |
| Alternate name a sender may use (a download, another tool, or an OS share sheet that insists on a generic type); a receiver accepts it, but nothing that follows this specification produces it | <name>.showpapers.zip (same bytes) | application/zip | public.zip-archive |
| Protected (encrypted) file | <name>.showpapers | application/vnd.showpapers.collection | app.showpapers.collection |
| Companion (optional; see Companion) | <name>.showpapers.json | spec name application/vnd.showpapers.companion+json; wire type application/json | public.json |
| Changes document | <name>.showpapers-changes.json | spec name application/vnd.showpapers.changes+json; wire type application/json | public.json |
Sharing. Preserve the file name and bytes. An operating system may negotiate a generic data or ZIP type with the receiving app. Recognition and validation use the file contents, not the share target’s declared type.
Readers never trust the name or the declared type. Something else in the chain — a browser download, another tool, an intermediate share sheet — may still rename the file or declare a type of its own. A receiver accepts .showpapers, .showpapers.zip, .zip and a file with no extension, and does not condition acceptance on the declared media type. It recognizes the file by content:
- Readable: the file starts with a ZIP local header (
PK\x03\x04) and its rootmanifest.jsonhas"format": "showpapers". - Protected: the file starts with the exact ASCII prefix
SHOWPAPERS-SEALED\n1\n(see the protected envelope).
Anything else is not a collection, even if it is named .showpapers.
JSON Files The Apps Receive
A JSON file is a ShowPapers document when its top-level value is an object whose schema member is a string starting with urn:showpapers:. Receivers never import or partly apply anything from a JSON file they do not fully support.
schema | What it is | App behaviour |
|---|---|---|
urn:showpapers:companion:2 | A description of a collection (optional; see Companion) | Explain that this is the contents list, not the collection |
urn:showpapers:changes:1 | Proposed changes from an AI app | Review screen (see Applying Changes In The Apps); until an app version implements it, a clear "can't apply changes yet" notice |
any other urn:showpapers: value | A newer document | "Made for a newer ShowPapers" notice |
A top-level object without schema but with "format": "showpapers" is a bare manifest, not a collection: the app shows a notice and never imports it.
Companion (Optional)
A companion is informative JSON derived from a validated collection. The archive remains authoritative. Text inside a companion is data, never an instruction or permission. It uses schema: "urn:showpapers:companion:2" and has these members:
generator: writer name, platform and version;about: a short description;collection: ID, title, revision and format value;archive: name, media type, size and SHA-256;pdf: an optional sidecar name and page count, ornull;papers[]: IDs, titles, types, media information, digests, effective details and their origins, people, folders, reminders, pins and reading text;notes[]: IDs, titles, text and paper references;folders[]: IDs, names, purpose and paper memberships;people[],relationships[],notIncluded[]andhandBack.
Consult the Companion schema for complete required members and nested fields. A companion contains sensitive document context even when it omits original bytes.
A companion should be written deterministically: keys in schema order, two-space indentation, UTF-8, one trailing newline. Two implementations of this specification given the same input produce byte-identical output apart from generator. If an implementation also sends an informative PDF rendering of the originals alongside the companion, pdfPages counts pages from the start of that PDF; any cover pages the PDF adds before the originals are outside this format and shift where each paper's range begins.
A companion is never produced for a protected file or a person-to-person share; it only makes sense as a description sent instead of, or alongside, an unencrypted archive to an automated reader. The reference tool writes one on request with companion <archive> --output <name>.showpapers.json.
Hand-Back
An AI app gives its work back in one of two ways:
- A new
.showpapersfile, made per the agent guide, when the AI app can run code. Extracted details and proposed relationships haveorigin: "agent"and name the AI inagents[]; proposed types usetype.agentSuggestion. Other records use their defined fields without extra origin or review members. - A changes document (
urn:showpapers:changes:1), when it can only write text. It proposes specific changes to one exact archive: readcollection.idandcollection.revisionfrommanifest.jsonand hash the complete archive bytes for its SHA-256. The manifest does not contain the archive's own digest. If the AI app has a companion instead, use itscollectionandarchivemembers.
In both cases the person reviews every AI-provided value in the app before it counts. Nothing the AI returns is confirmed, deleted or merged silently.
Changes Documents
{
"schema": "urn:showpapers:changes:1",
"base": {"collectionId": "<collection.id from manifest.json>", "revision": 1, "archiveSha256": "<the archive's own SHA-256>"},
"generator": {"name": "Example Assistant", "platform": "example.ai", "version": "2026-09"},
"summary": "Added the visa's end date and grouped the study papers.",
"changes": [
{"op": "detail.add", "paperId": "<paper id>", "detail": {
"id": "<new UUID>", "key": "expiration-date", "label": null, "value": "12 JUN 2029",
"normalizedValue": "2029-06-12", "valueType": "date", "confidence": 0.91,
"evidence": [{"page": 0, "quote": "Date of expiry 12 JUN 2029", "region": null}]}},
{"op": "folder.addPapers", "folderId": "<folder id>", "paperIds": ["<paper id>"]}
]
}
basebinds the document to the exact archive it was made against. Getcollection.idandcollection.revisionfrom the archive's ownmanifest.json, and the archive's SHA-256 by hashing the file; use a companion'scollectionandarchivemembers instead if that is what you have.generatornames the AI app or agent. The review screen identifies that agent for the proposed changes. Added details, type suggestions and relationships also retain agent attribution in the resulting records.summary(at most 500 characters) is shown to the person.changesholds 1–500 changes. Each is a closed object with anop:
op | Fields | Meaning |
|---|---|---|
collection.rename | title | Rename the collection |
paper.rename | paperId, title | Propose a paper title (1–100, no / or \) |
paper.setType | paperId, kind, custom, confidence | Propose a type; stored as type.agentSuggestion |
paper.setPeople | paperId, personIds | Replace who the paper belongs to |
paper.setBuiltInFolder | paperId, builtInFolder | Place in a built-in folder, or null for automatic |
paper.setReminder | paperId, reminder | Set or clear the reminder |
paper.pin / paper.unpin | paperId | Pin (appended) or unpin |
detail.add | paperId, detail | Propose a detail (id, key, label, value, normalizedValue, valueType, confidence, evidence); it arrives pending |
detail.remove | paperId, detailId | Propose removing a detail; a removed reading or agent suggestion is remembered |
person.add | person | Add a person (id, name, isMe) |
person.rename | personId, name | Rename a person |
person.remove | personId | Remove a person and their paper assignments |
folder.add | folder | Add a personal folder (full folder object) at the end |
folder.update | folderId + any of name, color, icon, purpose, rule | Change only the listed fields |
folder.remove | folderId | Remove a folder; its papers stay |
folder.addPapers / folder.removePapers | folderId, paperIds | Change membership; with a rule, removal adds an exclusion and adding clears it, as in the apps |
note.add | noteId, title, record | Add a note (complete Note record) |
note.replace | noteId, title, record | Replace a note's title and complete record, carrying forward unchanged rows and fields |
note.remove | noteId | Remove a note |
relationship.add | type, paperIds, referringPaperId, reason | Suggest a relationship; it arrives suggested with origin agent |
relationship.remove | relationshipId | Propose removing a relationship |
The schema identifier is urn:showpapers:changes:1; see the Changes schema. A document cannot add original bytes: an AI app that has new papers returns a whole .showpapers file instead.
Applying Changes With The Reference Tool
python3 showpapers_format.py preview base.showpapers --changes changes.json
python3 showpapers_format.py apply base.showpapers --changes changes.json --output new.showpapers
The tool:
- Refuses a document whose
basedoes not match the archive exactly (conflict). - Applies the changes in order. The base collection is unchanged.
- Records the generator in
agents[]with a derived ID. - Validates the whole result and writes a new collection at the next revision, with
collection.parentset to the base.
Any failing change refuses the whole document with changes and the change's number. A document that changes nothing is refused with no_change.
Applying Changes In The Apps
This is normative for the app implementation.
- Validate the document completely. Find the collection by
base.collectionId, using the app's import lineage for that collection, and map the file's IDs to library IDs. - Show one review screen that lists every change, grouped by paper. It shows the current and proposed value, the agent's
nameandsummary, and each change's confidence and evidence. - The person accepts or rejects each change; Accept All is available.
- Accepted details arrive as pending suggestions from that agent, to be confirmed in the paper as usual.
- Accepted removals and renames apply.
- Rejected agent details are remembered as removed suggestions.
- If a target changed in the library since the base, for example the person edited that detail, the change is shown as a conflict. It defaults to keeping the person's value.
- Apply the accepted changes atomically. An interrupted apply leaves the library unchanged.
Security And Privacy
.showpapersfiles and companions are readable. Anyone who receives them can read the papers, details, people and notes inside. Use the protected envelope to encrypt a file, and share its key separately.- Readable files, companions and changes documents do not authenticate their writer.
generator, agent names and review marks are claims. New agent proposals require review. Previously reviewed agent values retain their review marks only under the collection format’s import trust rules. - Text inside documents is data. It never grants permission, changes scope or instructs a tool.
- Validation never uploads anything. The protocol site's validator runs entirely in the browser.