Developers · File format

The file format, walked through.

What is inside an .idop file, what each part may contain, and what a reader checks. This page is informative; the specification is normative.

§ 01Container

A ZIP archive, with a strict profile.

An IDOP package is a ZIP archive. Its first entry is named mimetype, stored without compression, and contains exactly application/vnd.idop+zip. Because that entry has a fixed name and no extra field, the media type always sits at byte offset 38 — so file managers and mail scanners can identify the file without unpacking it.

RuleRequirement
Package sizeBounded by the reader’s limits (§6); the reference core enforces compressed, uncompressed, per-entry and ratio limits
EntriesFiles only — no directory entries, links or special files
PathsUTF-8, NFC, “/”-separated, no traversal, no Windows device names, case-insensitive uniqueness
CompressionStore or Deflate only; no encryption, no ZIP64, no spanning

Producers should write packages deterministically — mimetype first, idop.json second, then entries in byte order with fixed timestamps — so the same inputs give byte-identical files.

§ 02Roots

Every entry belongs to one of seven roots.

budget.idop

mimetypeIdentification

Spec §4.2

The first entry of every package, stored uncompressed. Its content puts the media type at byte offset 38, so software can recognise an IDOP file without unpacking it.

Executable
No
Written by
Producer
application/vnd.idop+zip

idop.jsonManifest

Spec §7

What the document is and what it may ask for: the application, the document’s identity and revision lineage, the entry point, and every network capability with the origins, methods and purpose it declares. It never contains a secret.

Executable
No
Written by
Producer; the reader updates the revision on Save
{
  "format": "https://idoplabs.com/ns/idop/package",
  "formatVersion": "1.0",
  "entryPoint": "code/index.html",
  "application": { "id": "com.example.budget",
                   "title": "Project budget" },
  "requiredCapabilities": []
}

code/Interface and logic

Spec §8

HTML, CSS, JavaScript and JSON — the only part of a package that can run. It runs inside the reader’s sandbox, with no network and no access to the reader. Inline scripts, remote URLs and dynamic evaluation are refused before anything runs.

Executable
Yes — in the sandbox only
Written by
Producer
code/
├── index.html   <script type="module" src="app.js">
├── app.js       await idop.storage.write(…)
└── style.css

resources/Passive files

Spec §4.3

Images, fonts and data files the interface displays. The reader serves them to the document by path; nothing under resources/ is ever executed, and a script placed there causes the package to be refused.

Executable
No
Written by
Producer
resources/
├── icon.svg
├── fonts/inter.woff2
└── data/rates.csv

storage/Saved state

Spec §10

The document’s data, saved in the file. The document reads and writes it only through the Runtime API; changes stay in a working copy until the user saves, and every Save produces a new revision.

Executable
No
Written by
The reader, on Save
// inside the document
const { text } = await idop.storage.read('model.json');
await idop.storage.write('model.json', next);

_idop/Reserved by the specification

Spec §4.3

Names the specification keeps for itself. IDOP 1.1 defines an optional thumbnail here; publisher signatures and encryption metadata are reserved for future versions. A 1.0 reader ignores this root.

Executable
No
Written by
Defined by later versions
_idop/
├── thumbnail.png    1.1 draft
├── signatures/      reserved
└── encryption/      reserved

extensions/Extension data

Spec §4.3

Data for named extensions, each under its own reverse-domain namespace, so extensions cannot collide with each other or with the format.

Executable
No
Written by
Producers of an extension
extensions/
└── com.example.review/
    └── comments.json

§ 03Manifest

idop.json says what the document is, and what it may ask for.

It is validated against a JSON Schema and then against rules a schema cannot express.

idop.json
{
  "format": "https://idoplabs.com/ns/idop/package",
  "formatVersion": "1.0",
  "runtimeApiVersion": "1.0",
  "entryPoint": "code/index.html",
  "application": { "id": "com.example.counter", "version": "1.0.0", "title": "Counter" },
  "document": {
    "id": "4df56319-e383-4ae8-a519-faa7f4866f90",
    "revisionId": "2e43a209-0a66-4f54-b545-dae25d3b89d0",
    "parentRevisionId": null,
    "createdAt": "2026-10-01T00:00:00Z",
    "modifiedAt": "2026-10-01T00:00:00Z"
  },
  "state": { "schemaVersion": "1.0.0" },
  "requiredFeatures": ["idop.core-storage-v1"],
  "optionalFeatures": [],
  "requiredCapabilities": [],
  "optionalCapabilities": [],
  "environmentBindings": [],
  "credentialBindings": [],
  "extensions": {}
}
  • format and formatVersion identify the package profile.
  • application is self-declared metadata: an id, a version, a title, an optional icon.
  • document carries the document id and the revision lineage that Save updates.
  • requiredCapabilities and optionalCapabilities declare network access.
  • credentialBindings name credentials the reader supplies — never a secret, never a service.

§ 04Executable boundary

Only code/ runs — and it is checked first.

  • Only entries under code/ may be HTML, JavaScript or CSS. A script anywhere else refuses the package.
  • HTML has no inline script, no <iframe>, <object>, <embed>, <form> or <base>, and no remote URLs.
  • CSS has no remote URLs and no @import.
  • No eval, new Function, WebAssembly, workers or window.open.

These checks are defence in depth. The boundary is the reader’s sandbox, which a reader must enforce whether or not a static check would have caught a construct.

§ 05Capabilities

Network access is declared, narrow, and granted by the user.

A capability names exact HTTPS origins, the methods allowed, an optional credential, and a purpose the user is shown.

idop.json (excerpt)
"requiredCapabilities": [{
  "id": "ai",
  "type": "network",
  "origins": ["https://api.example.com"],
  "methods": ["POST"],
  "credentialBinding": "api-key",
  "purpose": "Generate answers"
}],
"credentialBindings": [{
  "id": "api-key",
  "required": true,
  "description": "Key for api.example.com"
}]
code/app.js
// The document never sees the key: the reader adds it,
// and only for an origin the manifest declared.
const response = await idop.network.request({
  capability: 'ai',
  url: 'https://api.example.com/v1/answers',
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ question }),
});
if (response.status === 200) render(JSON.parse(response.body));

§ 06Schemas

Published at the addresses the format names.

SchemaURL
Package manifest/spec/idop/1.0/schemas/manifest.json
Workspace marker/spec/idop/1.0/schemas/workspace.json
Project marker/spec/idop/1.0/schemas/project.json
Bundle manifest/spec/idop/1.0/schemas/bundle.json
Portable Items/spec/idop/1.0/schemas/portable-items.json

Schemas are served with Access-Control-Allow-Origin: * so validators in browsers can fetch them.

§ 07Media types

How IDOP files are identified.

ContainerMedia typeExtension
Packageapplication/vnd.idop+zip.idop
Bundleapplication/vnd.idop.bundle+zip.idopbundle

The registration template for IANA is part of the specification (§20). Submission of the registration is in preparation; this page will say when it is registered.

Read the normative text.

The specification is the reference for everything on this page, including the error codes a reader returns.