Open Format guide

Specification

Linko Open Format — Schema v1.1

The exact contract for Linko exports: how a package is laid out, what every field means, and what an importer must do. Any tool that follows it can read and write Linko data.

Status: Stable v1.1 — 2026-09-30 (v1.0 — 2026-05-18)

Compatibility: Linko exports schema_version: "1.1" and imports "1.0" and "1.1". 1.1 only extends the Resource type vocabulary (post, tool; online_course retired). Future minor versions may add optional fields or values only after importer support is explicitly implemented; unsupported versions must fail clearly rather than being read silently.


Purpose

This document is the authoritative, machine-friendly specification of Linko's exported vault format. Any tool — Linko's own importer, third-party scripts, AI agents, or future clients — that conforms to this spec can read and write Linko vault data with functional equivalence within v1's defined scope.

The spec is the contract behind Linko's promise:

"Linko handles intelligent organization; users always own their original content."


1. Versioning

  • The schema follows semantic-ish versioning: MAJOR.MINOR.
  • Major bumps (e.g., v1 → v2) introduce new top-level directories or new required fields. Old importers MUST NOT read major-newer packages silently — they must error.
  • Minor bumps (e.g., v1.0 → v1.1) may add optional fields or vocabulary values; Linko's importer accepts only the minor versions it implements (currently "1.0" and "1.1").
  • Every export package declares its version in linko-schema.json.

2. Vault Layout

A v1 export package is a directory (typically delivered as a ZIP) with the following structure:

my-linko-vault/
├── linko-schema.json          # REQUIRED — package manifest
├── export-warnings.json       # RECOMMENDED — exporter warning report
├── notes/                     # REQUIRED — one file per note
│   ├── <yyyy-mm-dd>-<slug>.md
│   └── ...
├── resources/                 # REQUIRED — one file per resource
│   ├── <slug>.md
│   └── ...
└── README.md                  # RECOMMENDED — human-readable export notes

Filename conventions:

  • Notes: <creation-date>-<slug>.md where slug is a URL-safe lowercase variant of the note title (max 80 chars). If two notes collide on date+slug, append -2, -3, etc.
  • Resources: <slug>.md where slug is derived from title (max 80 chars), with collision suffixes as above.
  • All filenames MUST be UTF-8 and ASCII-safe (replace forbidden chars <>:"/\|?* with _).
  • Filenames are for humans only. Importers MUST use frontmatter UUIDs, not filenames, as object identity.
  • UUIDs SHOULD NOT be included in filenames in v1 exports.

Empty directories MUST still exist (the importer uses their presence to assert v1 compliance).

Exporters SHOULD generate README.md by default. It should explain the schema version, basic import instructions, strict import behavior, and the fact that private notes are exported as plaintext for the account owner. Importers MUST NOT require README.md.

Exporters SHOULD generate export-warnings.json by default. Importers MUST NOT require it when the manifest does not declare a warning report, but tools MUST surface it to users when the manifest declares it and the file is present.


3. linko-schema.json — Package Manifest

This file is the entry point for any importer. It MUST exist at the root of every package.

Schema

{
  "schema_version": "1.1",
  "generated_at": "2026-04-22T10:00:00Z",
  "generator": "linko-exporter/1.0",
  "export_id": "4d967c2a-3d6a-42a7-96b5-1ad2a8fbf1a1",
  "linko_origin_signature": "opaque-server-generated-signature",
  "contents": {
    "notes": {
      "count": 342,
      "directory": "notes/"
    },
    "resources": {
      "count": 58,
      "directory": "resources/"
    },
    "projects": {
      "count": 12,
      "source": "manifest"
    },
    "tags": {
      "count": 127,
      "source": "frontmatter"
    },
    "warnings": {
      "count": 0,
      "file": "export-warnings.json"
    }
  },
  "projects": [
    {
      "id": "222e4567-e89b-12d3-a456-426614174001",
      "name": "Product",
      "scope": "custom",
      "parent_id": null,
      "description": "User-owned product work"
    },
    {
      "id": "222e4567-e89b-12d3-a456-426614174002",
      "name": "Linko",
      "scope": "custom",
      "parent_id": "222e4567-e89b-12d3-a456-426614174001"
    }
  ]
}

Field reference

Field Type Required Description
schema_version string Yes "1.1" for this spec ("1.0" packages remain importable)
generated_at ISO 8601 datetime (UTC) Yes Export timestamp
generator string Yes <tool>/<version>; e.g. linko-exporter/1.0
export_id UUID string Yes Identifier for this export package
linko_origin_signature string No Opaque server-generated proof used by Linko to recognize a full export created for the importing account. It contains no account identity and is not required for third-party v1 packages.
contents.notes.count integer Yes Sanity check — must equal actual file count
contents.notes.directory string Yes Always "notes/" in v1
contents.resources.count integer Yes Sanity check
contents.resources.directory string Yes Always "resources/" in v1
contents.projects.count integer No Number of the user's Tags declared in manifest projects
contents.projects.source string No Always "manifest" when Tag hierarchy metadata is present
contents.tags.count integer Yes Number of unique tag IDs referenced in note/resource frontmatter
contents.tags.source string Yes Always "frontmatter" in v1
contents.warnings.count integer No Number of exporter warnings
contents.warnings.file string No Warning report path, usually "export-warnings.json"

The manifest MUST NOT include user UUID, email, username, auth identifiers, or other PII. Import targets are determined by the logged-in account that invokes the importer.

Conformance vs current Linko enforcement: Linko validates the required manifest metadata, fixed directory declarations, Note, Resource, Tag (projects) and tag reference counts, and any declared warning report before writing. Packages that omit the optional projects or warnings sections remain valid v1 packages for backward compatibility. Unsupported schema versions still fail clearly.

Manifest projects

projects is an optional additive v1 field for the user's Tag hierarchy. The manifest key is projects for compatibility; it holds the user's Tags (called Projects in earlier versions of Linko). Linko exports every Tag the user owns, including Tags that are not currently attached to a Note or Resource. Adapters should use the same normalized structure when a source exposes folders, collections, notebooks, or other user-authored organization that must preserve parent-child structure. Packages without projects remain valid v1 packages and import with the older flat tag behavior.

Each entry has this shape:

Field Type Required Description
id UUID string Yes Stable Tag identifier. Importers reuse the target user's Tag with this UUID or create one.
name string Yes Tag display name. Same names are allowed under different parents.
scope enum Yes Must be "custom" in v1. Topics are not valid entries.
parent_id UUID string or null Yes Parent Tag id from the same manifest projects list, or null for a top-level Tag.
description string No The Tag's description, when the user wrote one.
icon_key string or null No Portable user-selected Tag icon key. It must match Linko's lowercase ASCII icon-key pattern.
hidden_in_workspace_nav boolean No User's workspace navigation visibility preference; defaults to false when omitted.

Importers MUST validate the Tag hierarchy before writing:

  • projects entries must have unique UUIDs.
  • Every parent_id must reference another Tag in the same projects list.
  • Duplicate Tag names under the same parent are blocking package errors; the same name under different parents is valid.
  • References to Topics, self edges, cycles, and parent edges to a Topic or to another user's Tag are blocking package errors.
  • Created or updated Tags must be owned by the importing user, never Topics.
  • An importer that keeps derived data for Tags (such as search embeddings) should refresh it for the Tags it creates or updates.

Note and Resource tags remain the authority for which Tags an object belongs to. The manifest-level projects list defines Tag metadata and hierarchy; it does not by itself attach a Note or Resource to a Tag.


4. Note Files

Each note is one Markdown file with YAML frontmatter.

Format

---
id: 550e8400-e29b-41d4-a716-446655440000
title: "Decision points for AI agent architecture"
created: 2026-03-15T10:32:00Z
updated: 2026-03-15T10:32:00Z
private: false
is_voice_note: false
source:
  type: manual
  detail: web_app
category: personal_thought
tags:
  - id: 111e4567-e89b-12d3-a456-426614174000
    name: "ai/agents"
    scope: public
  - id: 222e4567-e89b-12d3-a456-426614174001
    name: "product/linko"
    scope: custom
resources:
  - id: 333e4567-e89b-12d3-a456-426614174002
    title: "GPT-5 Technical Report"
---

# Decision points for AI agent architecture

Notes after reading the GPT-5 technical report...

Frontmatter field reference

Field Type Required Description
id UUID string Yes Stable note identifier; Linko keeps it as the note's own ID
title string Yes Note title; may be empty string but field MUST exist
created ISO 8601 datetime Yes Original creation time, UTC
updated ISO 8601 datetime Yes Last modification time, UTC
private boolean Yes Product-level privacy flag
is_voice_note boolean No Default false
source object No How this note entered Linko; see below
category string No What kind of note this is; see below
voice_transcript string No Original voice transcript for voice notes, when available
tags array of {id, name, scope} objects Yes May be empty array; MUST NOT be omitted
resources array of {id, title} objects Yes May be empty array; MUST NOT be omitted. title is a human-readable snapshot; id is import authority
links array of {id, kind, context?} objects No Note-to-note references; id is the target Note UUID

source and category

source describes how the note entered Linko. Suggested source.type values include manual, imported, ai_created, extension_capture, voice_transcription, and api. source.detail may hold a more specific entry point such as web_app, mobile_app, chrome_extension, obsidian, readwise, weread, linko_voice, or wechat_import.

category describes the primary content type of the note. Linko exports its note type here: insight, excerpt, idea, todo, or log, and omits the field when a note has no type. Linko's importer restores those values as the note type chosen by the user, and treats the legacy values highlight and quote as excerpt. Other legacy values that earlier exports or adapters produced (personal_thought, conversation, ai_conversation, voice_note, imported_text, summary, other) remain valid input but carry no content type; capture method belongs in source.

These values are intentionally extensible controlled vocabularies. The suggested values above are valid for v1, but Linko may add or adjust values as product needs evolve. Exporters SHOULD populate source and category when known. Importers MUST preserve source when a Linko origin signature verifies for the target account, MUST map category to the note type as described above, and MUST tolerate unknown string values for forward compatibility. Cross-account Linko packages, external packages, and adapter-generated imports MUST persist source.type = imported on the target Note; source.detail should identify the import route. This keeps target-side capture filters aligned with how the Note entered the target account while retaining exact source fields for same-account restore.

Body

The Markdown body following the closing --- is the note's content as written by the user. Linko will not transform it (no auto-linking, no canonicalization beyond ensuring valid Markdown). On import, the Note title comes from frontmatter title; the body after frontmatter is the Note content.

Private notes: private: true means the note is private in Linko. In Linko, private notes MUST be stored encrypted server-side. V1 exports are designed for the account owner and remain human-readable, so Linko writes decrypted plaintext title and body into the Markdown file. Export UI MUST warn that the package may contain private plaintext content. Package-level encryption is out of scope for v1.

Voice notes: The Markdown body is the note body shown in Linko, which may be the organized note generated from the voice input. When available, the original transcript SHOULD be exported separately as frontmatter voice_transcript. V1 does not include original audio binaries. The is_voice_note: true flag preserves the type.

Body Markdown

The dialect of a note body: what Linko's editors read and write, inside Linko and in exported Note files.

Unchanged body. When the user has not changed a note's body, every surface sends the stored Markdown byte for byte, never a re-serialised copy. A re-serialised body is saved only after a real edit. The API's own write step is outside this rule: it strips raw HTML tags from every body it saves (an injection guard), so a body that holds raw HTML (such as <u>) loses its tags on any save, edited or not; every other byte is stored as sent. "Not changed" means the editor's document is still the one it opened: typing and undoing, IME composition, plugin transactions and title-only edits do not count, while removing a mark the writer cannot express (such as strikethrough on web) does. The web note editor, the note page, the ChatGPT app editor, the extension's restored drafts, the native mobile editor and its fallback editor all follow it, and their save-time normalization (trimming, blank-line runs) applies only to an edited body.

Base. CommonMark plus GFM tables, task lists, strikethrough and autolinks, with three amendments and three Linko conventions:

  • A single newline is a line break (breaks: true), not a space.
  • CJK-friendly emphasis: ** and * open and close beside CJK punctuation (**结论:**先写), as markdown-it-cjk-friendly, marked-cjk-friendly and remark-cjk-friendly read it.
  • Bare addresses link only with a scheme (https://…) and run to the next space, as GFM autolinks do, so CJK text right after an address is part of it. Writers write an address that text follows as an autolink (<https://…>,) or a link.
  • Empty paragraph: U+200B alone on a line is an intentionally empty paragraph. A run of them saves as one.
  • Private images: ![alt](linko-file://<id>) references a private image. Clients keep the reference; the API may send a signed URL instead.
  • Headings: a note has one heading level, written ##; # is reserved for the note title. Readers open # to ###### as that one heading, and the next edit writes it ##.
  • No underline. Markdown has none and no editor offers it. Readers open <u>…</u> as plain text (the words stay); no writer emits <u>. Clients send a stored <u> back unchanged until the note is next edited (Unchanged body), and cards may still show it until then.

Canonical forms. What a writer saves for each construct after an edit:

Construct Saved as Also read
Paragraph Text, one blank line between paragraphs
Line break A single newline Two trailing spaces, \ before the newline, <br>
Bold **text** __text__
Italic *text* _text_
Strikethrough ~~text~~
Inline code `code`, with a longer backtick fence when the code holds backticks
Code block A fenced block (``` plus an optional language) Indented code
Heading ## text # to ######
Link [text](address "title"); a link whose text is its address as [address](address) Autolinks, bare addresses
Image ![alt](address "title")
Bullet list - item, nested items indented to the item's text; the second of two adjacent lists uses * *, +
Ordered list 1. item, keeping its start number; the second of two adjacent lists uses )
Checklist - [ ] item and - [x] item, also in ordered lists [X]
Quote > on each line; > alone between its paragraphs
Table A GFM pipe table: header row, ` ---
Thematic break --- ***, * * *
Underline Not written: the words only <u>…</u>
Raw HTML Its text Editors open it as its text; cards render only an allow-list of tags; the API strips tags on save
Literal text As typed, escaping only what a reader would take as syntax

Older content follows the same rules: bodies from the Draft.js editor (2024–2025) that were never converted are JSON text, which every editor opens and saves as text; Markdown written by the Draft.js converter (html2text) reads as ordinary Markdown.

Export Warnings

Open Format exporters SHOULD complete a package whenever possible. Object-level issues SHOULD be recorded in export-warnings.json instead of failing the whole export:

  • If an optional field cannot be exported safely, skip that field and add a warning.
  • If a single Note or Resource cannot be exported safely because required data is unreadable, skip that object and add a warning.
  • If private Note title/body decryption fails, exporters MUST NOT write placeholder text such as "Encrypted" into the Markdown file. They SHOULD skip that Note and add a warning.
  • Whole-package failure SHOULD be reserved for system-level errors such as database connection failure, ZIP write failure, or manifest/schema generation failure.

Warning report shape:

{
  "generated_at": "2026-05-07T04:30:00Z",
  "warnings": [
    {
      "code": "field_skipped",
      "object_type": "note",
      "object_id": "111e4567-e89b-12d3-a456-426614174000",
      "field": "voice_transcript",
      "message": "Voice transcript could not be decrypted; note body was exported."
    }
  ]
}

Cross-references

  • tags[].id is a stable tag UUID; tag objects are embedded directly in frontmatter in v1
  • resources[].id MUST match a resource UUID in resources/ (i.e., a file's frontmatter id). resources[].title is informational only and MUST NOT be used as identity.
  • links[].id MUST be a valid Note UUID string and SHOULD match another Note UUID in the same package. Missing link referents SHOULD be skipped with a warning because note links are optional auxiliary structure.
  • Strict import MUST validate required tag/resource references; missing required resource referents are errors.

Supported links[].kind values are reference, builds_on, and contrasts. Importers SHOULD skip unknown link kinds with a warning rather than failing the package. links[].context is optional short text explaining the relationship; non-string context should be dropped with a warning.


5. Resource Files

Each resource is one Markdown file with YAML frontmatter.

Format

---
id: 333e4567-e89b-12d3-a456-426614174002
resource_id: 444e4567-e89b-12d3-a456-426614174003
title: "GPT-5 Technical Report"
type: article
author: "OpenAI"
year: 2025
month: 8
platform: "arxiv"
url: "https://arxiv.org/abs/..."
image_url: "https://..."
language: en
description: "Technical details of GPT-5 architecture..."
created: 2026-03-15T10:32:00Z
updated: 2026-03-15T10:32:00Z
progress: 75
total_length: 100
custom_title: "GPT-5 paper — my highlights"
tags:
  - id: 555e4567-e89b-12d3-a456-426614174004
    name: "highlights"
    scope: custom
---

# GPT-5 Technical Report

OpenAI · Article · 2025
[Open resource](https://arxiv.org/abs/...)

Frontmatter field reference

Field Type Required Description
id UUID string Yes Stable user-resource identifier: the user's own link to this resource, which holds their progress, custom title and tags
resource_id UUID string Yes Stable global resource identifier, the same for every account that saved this resource
title string Yes Resource title
type enum Yes One of: book, article, post, video, podcast, tool, other (1.1). online_course is a 1.0 value that importers still accept and read as video; exporters no longer write it.
author string No
year integer No Publication year
month integer No Publication month (1–12)
platform string No e.g., arxiv, youtube; only for non-book types
url URL No External link; omitted for books when Linko only has an internal provider lookup URL such as Google Books API or Douban
image_url URL No External cover image reference. It is not a guarantee that the image remains available. Linko private cover storage keys, signed URLs, and cover binaries are never exported in v1.
language string No ISO 639-1 code (en, zh, etc.)
description string No Resource description
created ISO 8601 datetime Yes When user added this resource
updated ISO 8601 datetime Yes
progress integer No 0–100 (percentage); default 100
total_length integer No Default 100
custom_title string No User's renamed title for this resource
tags array of {id, name, scope} Yes User-visible tags applied to this resource; may be empty

V1 intentionally excludes system-only resource data: Linko's own topic suggestions, author details, the resource-level privacy flag, and the record of how the resource was first added. They support internal recommendation and organization, future product features, or backend-only metadata, and are not portable Resource content. Source adapters may use a documented frontmatter source object when they need to preserve source provenance.

Body

The body provides a lightweight human-readable summary. It SHOULD NOT repeat long description content or structural fields such as tags, progress, or custom title. For resources, frontmatter is the import authority; importers MAY ignore the body and rebuild it from frontmatter.

For books, Linko may omit url when its stored link is only an internal provider lookup URL (for example Google Books API or Douban). ISBN is not part of v1 because Linko does not store it today; it may be added later as an optional field.


6. Tag References

V1 does not include a standalone tags.json. Tags are embedded in Note and Resource frontmatter as references.

Tag object

Field Type Required Description
id UUID string Yes Stable tag identifier
name string Yes Display name at export time
scope enum Yes public for Linko-maintained public tags; custom for user-created tags

V1 tag semantics

  • The same tag may appear in many files; importers should deduplicate by id.
  • Manifest contents.tags.count counts unique tag IDs referenced across all exported files.
  • public tags (Topics) MUST already exist in the target Linko. If a public tag UUID is missing, strict import records a warning and skips that tag reference.
  • For public tag references whose UUID exists in the target, the target's current name is authoritative; the embedded name is informational only (it preserves a snapshot for human reading and cross-tool compatibility, but importers MUST NOT use it to rename existing tags).
  • custom tags are user-owned. If a custom tag UUID is missing in the target account, strict import creates it from the embedded {id, name, scope} object.
  • For custom tag references whose UUID already exists in the target account, the embedded name is ignored (no rename via import). Tag rename happens only through Linko's UI.
  • If the target account already contains a custom tag with the same name but a different UUID, strict import MUST still create the new custom tag with its embedded UUID (so all references are preserved), and MUST emit a warning identifying the duplicate. v1 does not auto-merge tags by name; reconciling duplicate display names is left to the user.
  • In Linko, public tags appear as Topics, which Linko maintains, and custom tags as the user's own Tags. These are product names over the v1 scope field; they do not change v1 file semantics.
  • V1 preserves the parent-child relationships between the user's Tags when they are declared in manifest projects.
  • V1 does not preserve Topic descriptions or any tag translations (Tag descriptions travel in manifest projects).
  • V1 does not export derived hierarchy data (such as a Tag's full list of ancestors); importers MUST rebuild it rather than expect it.
  • A future additive version may introduce tag_edges.json, richer tag metadata, a projects/ directory, or Topic hierarchy semantics.

7. Round-trip Semantics

The defining promise of this format:

Export a vault → clear the database → import the same vault → the database state is functionally equivalent to before the export, restricted to v1's data scope.

"Functionally equivalent" means:

Preserved:

  • All Notes (id, title, body, dates, tags, resources, private, voice flag, and source/category when present; cross-account imports normalize the target source type to imported)
  • All Resources in an empty-target round trip (global resource identity and metadata + user-resource identity and relationship fields)
  • All user-visible tag references (id, scope, and the embedded name snapshot); display names on import follow §6 tag authority rules
  • The user's Tag hierarchy declared in manifest projects
  • Tag descriptions, icon keys, and workspace visibility preferences from manifest projects, when present
  • All cross-references between the above

Not preserved (intentional, documented):

  • Internal: AI suggestion history
  • Derived: embeddings and other derived search and hierarchy data
  • The Topic tree in v1
  • Topic descriptions and tag translations in v1
  • Note edit counters
  • Social: likes, follows, push tokens
  • Billing / membership state
  • Auth tokens
  • Encrypted-form fields (private notes are re-encrypted on import)
  • Voice audio binaries
  • Resource original files / images, including private cover storage objects

A targeted round-trip test exists for the preserved set and should be run for Open Format changes. The full Open Format exporter/importer and round-trip suites are part of the focused verification for contract changes.


8. Conformance

A tool is v1-conformant if it:

  1. Reads linko-schema.json first and refuses unsupported versions clearly
  2. Validates contents.*.count against actual file counts
  3. Resolves note/resource cross-references during import
  4. Applies V1 tag import rules for public and custom tag references
  5. Does not rely on unknown optional frontmatter fields for v1.0 behavior; future minor-version support should warn or preserve explicitly rather than silently dropping meaningful data
  6. Does not infer, repair, or fabricate missing required values in strict mode
  7. Round-trips its own exports without data loss

Verified Linko-generated full-account exports may exceed the general 500-item reliability guard used for external source imports. Their import preflight reports a warning instead of blocking the complete package. A manifest generator value alone is not sufficient to receive this exception. External Open Format packages remain subject to the general guard and should be split by the source tool when necessary.

Importers MAY also apply transport-safety limits for raw ZIP bytes, expanded ZIP bytes, and member count. Linko currently limits Open Format imports to 100 MiB compressed input, 500 MiB expanded content, and 20,000 ZIP members; these limits are separate from the Note/Resource item-count policy.

Import modes

V1 defines only strict import:

  • Validate the manifest, schema version, directory layout, required files, required fields, UUID formats, counts, and cross-references.
  • If validation fails, abort the entire import before writing data.
  • Return a structured error report that identifies every blocking issue found.
  • Support dry_run so users can validate a package without writing to the database.
  • Importing the same package multiple times MUST be idempotent by UUID.
  • Drift protection (stale-package safety): import authority is object-specific:
    • For Note.id, when the UUID matches an existing Note in the target account, the importer MUST compare Note updated timestamps. If the target's updated is newer than the package's, skip that Note and emit a warning ("target object newer than package — kept target version"). If timestamps are equal, treat the Note as unchanged and do not physically rewrite it. Only if the package's updated is newer than the target's should the importer overwrite the target Note with package data.
    • For Resource file id (the user-resource), drift comparison applies only to user-owned relationship fields: created, updated, progress, total_length, custom_title, and tags. If the target user-resource is newer, skip those user-owned fields and emit a warning. If timestamps are equal, treat the user-resource as unchanged. Only if the package's updated is newer should the importer overwrite user-owned relationship fields from the package.
    • For global resource_id, V1 import is conservative because global Resource facts may be shared across accounts. If the target lacks resource_id, create the global Resource from package metadata. If the target already has resource_id, attach the user-resource to the existing global Resource and MUST NOT overwrite global Resource metadata from a user import. If package global metadata differs from target metadata, the importer MAY emit a warning.
    • Tag references follow §6 — tag names are not subject to drift comparison because they are never overwritten via import.
    • Importers MUST NOT silently overwrite newer user data with stale package data.
  • Additive only — never delete: objects present in the target account but absent from the package MUST NOT be deleted. V1 import is upsert-only. Full restore from a package requires importing into an empty target account; v1 does not provide a "mirror" or "destructive sync" mode.
  • User-owned object IDs (Note.id, Resource file id, and custom tag IDs) are idempotent within the target account. Cross-account imports may remap user-owned IDs if they conflict in the target account, but MUST preserve all references through an import-local mapping.
  • Global resource IDs (resource_id) identify global Resource facts and may be reused across accounts. If the target database does not contain resource_id, V1 import creates a global Resource with that UUID from the exported frontmatter. V1 import MUST NOT perform heuristic resource deduplication by title, author, or URL; that can be added later as an explicit repair/reconciliation feature.

repair import is intentionally out of scope for v1. A repair importer may later recover user-edited or partially broken packages by filling missing fields, generating UUIDs, skipping bad references, or normalizing dates, but that behavior is not part of the Open Format v1 contract.


9. Reserved for Future Versions

These keys / directories MUST NOT be used by v1 implementations and are reserved:

Reserved Introduced in Purpose
subjects/ directory v2 Topic pages and their revisions
attachments/ directory v3 Binary content addressing
Frontmatter subjects: v2 Note → Topic page references
Frontmatter attachments: v3 Note → Attachment references
linko-schema.json attachment_index v3 sha256 → file mapping
tag_edges.json or tag parents v2+ Tag tree relationships

10. Examples

Linko's exporter, importer and round-trip tests are the current executable examples; an export from your own Linko account is a complete example package. A static reference vault can be added later when it becomes useful for third-party tooling.


11. Change Log

Date Version Notes
2026-04-22 1.0 Draft Initial spec
2026-05-01 1.0 Draft revision Removed manifest email, clarified human-readable filenames, added global Resource and user-resource UUIDs, made tags flat in v1, documented private plaintext export and strict import
2026-05-01 1.0 Draft revision Clarified compatibility semantics, optional README, and source/category round-trip preservation
2026-05-02 1.0 Draft revision Clarified user-owned UUID remapping and public/custom tag import behavior
2026-05-02 1.0 Draft revision Clarified README generation, source/category preservation, Note/Resource import authority, and Resource creation without heuristic deduplication
2026-05-02 1.0 Draft revision Marked source/category as extensible vocabularies and defined README default content
2026-05-06 1.0 Draft revision Closed four hardening gaps: (1) v1 import declared additive only — absent objects are never deleted; (2) drift protection — importer skips with warning when target updated is newer than package, preventing stale-package overwrites; (3) tag-name authority rules — public tag uses the target's name; custom tag name set on creation only, ignored thereafter; (4) cross-account custom-tag duplicate-name conflict — create new tag with embedded UUID, warn, no auto-merge
2026-05-06 1.0 Draft revision Follow-up review fixes: removed the note edit counter from v1 export scope; split drift/import authority between Note, user-resource, and global Resource metadata; aligned tag-name round-trip wording with tag authority rules; converted examples and promise text to English
2026-05-07 1.0 Draft revision Tightened import drift semantics: equal timestamps are unchanged and should not physically rewrite existing objects; only package-newer objects overwrite target data
2026-09-30 1.1 Resource type adds post and tool; online_course retired (imported as video, no longer exported). Linko exports 1.1 and imports 1.0 and 1.1
2026-10-25 1.1 Added Body Markdown: the body dialect, canonical forms, one ## heading level, no underline, and the unchanged-body Principle. Format version unchanged: existing bodies stay valid