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.
| Rule | Requirement |
|---|---|
| Package size | Bounded by the reader’s limits (§6); the reference core enforces compressed, uncompressed, per-entry and ratio limits |
| Entries | Files only — no directory entries, links or special files |
| Paths | UTF-8, NFC, “/”-separated, no traversal, no Windows device names, case-insensitive uniqueness |
| Compression | Store 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.2The 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+zipidop.jsonManifest
Spec §7What 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 §8HTML, 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.cssresources/Passive files
Spec §4.3Images, 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.csvstorage/Saved state
Spec §10The 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.3Names 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/ reservedextensions/Extension data
Spec §4.3Data 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.
{
"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": {}
}formatandformatVersionidentify the package profile.applicationis self-declared metadata: an id, a version, a title, an optional icon.documentcarries the document id and the revision lineage that Save updates.requiredCapabilitiesandoptionalCapabilitiesdeclare network access.credentialBindingsname 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 orwindow.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.
"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"
}]// 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.
| Schema | URL |
|---|---|
| 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.
| Container | Media type | Extension |
|---|---|---|
| Package | application/vnd.idop+zip | .idop |
| Bundle | application/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.