Worldlet Format GitHub issue
- Overview
- Top-Level Structure
- meta
- format and format_version
- properties
- classes
- records
- files
- Import Rules
- Minimal Valid Example
- Complete Example
vibecode
{"vibecode": { "doc": "worldlet", "role": "spec for the worldlet JSON file format — the portable serialization of a small mikobase used for sharing, shipping, and exchanging databases that fit comfortably as a single JSON document. Covers the top-level structure, every section (meta / format / properties / classes / records / files), import rules, and complete worked examples.", "audience": ["humans designing worldlet producers and consumers", "AI agents reading or emitting worldlet JSON directly"], "size_scope": "small_mikobases_only; a_separate_export_format_for_large_mikobases_is_planned_but_not_yet_designed", "key_concepts": ["non_temporal_default_no_history_block", "records_keyed_by_uuid", "classes_section_for_schema", "files_with_file_chunks_subsection_for_binary", "import_overwrites_on_uuid_match", "validation_errors_abort_atomically", "app_owns_conflict_policy_not_the_primitive"], "see_also": { "Puckai.md": "temporal worldlet shape used by Puckai sessions", "mikobase.md": "full mikobase model, temporal vs non-temporal mode" }, "example_universe": "Star Trek" }}
A worldlet looks like this — three records, no classes, no history, no files:
{
"format": "worldlet",
"format_version": "1.0",
"records": {
"1a000000-0000-0000-0000-000000000001": {
"bucket": {"name": "Picard, Jean-Luc", "rank": "Captain"}
},
"1a000000-0000-0000-0000-000000000002": {
"bucket": {"name": "Riker, William", "rank": "Commander"}
},
"1a000000-0000-0000-0000-000000000003": {
"bucket": {"name": "Data", "rank": "Lieutenant Commander"}
}
}
}
That's the whole format at its smallest. Everything below is optional detail layered on top.
Overview GitHub issue
vibecode
{"vibecode": { "section": "overview", "what_a_worldlet_is": "a complete non_temporal_mikobase serialized as one JSON object", "contains": ["classes_definitions", "records_with_buckets", "optional_files_and_file_chunks", "optional_meta_and_properties"], "size_scope": "small_mikobases_only; large_mikobases_will_use_a_different_export_format_tbd", "primary_use_cases": ["snapshot_for_sharing", "scenario_or_scratch_space", "puckai_exchange_format_subset"], "import_target": "non_temporal_mikobase_only; importing_into_temporal_raises", "history_handling": "no_version_history_in_non_temporal_shape; see_Puckai_md_for_temporal_shape" }}
A worldlet is a complete mikobase — classes, records, and files — packaged as a single JSON object. It is the standard format for sharing and distributing small mikobases. A separate export format for large mikobases is planned but not yet designed; if a mikobase is too big to ship comfortably as one JSON document, this is not the format to reach for.
This document describes the non-temporal worldlet shape — each record is stored as a single object with its current bucket; there is no version history. Non-temporal is the worldlet default and matches most use cases (snapshots of conversations, scenarios, scratch space). Temporal worldlets exist for cases that need to preserve history; see Puckai.md for that shape and mikobase.md for the full mode rules.
A worldlet is imported into a running mikobase. The importer creates the classes, inserts the records, and stores any file attachments. PKs are preserved exactly as exported, so references between records remain valid after import. A non-temporal worldlet imports into a non-temporal mikobase; importing into a temporal mikobase raises an exception.
Top-Level Structure GitHub issue
vibecode
{"vibecode": { "section": "top_level_structure", "required_keys": ["format", "format_version"], "optional_keys": ["meta", "properties", "classes", "records", "files", "file_chunks"], "key_order": "not_significant; order shown is conventional for human readability", "shape": "single_top_level_json_object" }}
{
"format": "worldlet",
"format_version": "1.0",
"meta": { ... },
"properties": { ... },
"classes": { ... },
"records": { ... },
"files": { ... },
"file_chunks": { ... }
}
A worldlet plays two roles: a serialized export of an engine-backed mikobase (SQLite in v1) and the live storage of the puck.uno/mikobase/worldlet engine. See mikobase.md § Worldlets: Mikobase on a microscale for the broader picture and the engine/format distinction.
A worldlet's required keys depend on its temporal flag (see mikobase.md § Temporal vs Non-temporal Mode):
- Non-temporal worldlets (the default —
temporalkey absent orfalse):recordsis required and carries each record's current bucket directly;historyis not part of the format. - Temporal worldlets (
"temporal": trueat the top level):historyis required;recordsis optional (the engine infers identity stubs from history if absent).
All other top-level keys default to empty structures if absent.
This document describes the non-temporal worldlet shape — records carry their current bucket directly. For the temporal shape with per-version history entries, see Puckai.md.
meta GitHub issue
vibecode
{"vibecode": { "section": "meta", "fields": ["name", "author", "version"], "purpose": "descriptive_metadata_about_the_worldlet" }}
Descriptive information about the worldlet.
"meta": {
"name": "Starfleet Personnel",
"author": "starfleet.com",
"version": "1.0.0",
"description": "Personnel records for Starfleet officers and ships.",
"created_at": "2364-01-01T00:00:00.000Z"
}
| Field | Required | Description |
|---|---|---|
name |
no | Human-readable name |
author |
no | UNS domain of the publisher |
version |
no | Semver string |
description |
no | Free-text description of the worldlet's contents |
created_at |
no | ISO 8601 timestamp of when the worldlet was exported |
format and format_version GitHub issue
vibecode
{"vibecode": { "section": "format_and_format_version", "fields": ["format", "format_version"], "purpose": "format_identity_and_versioning" }}
Two optional top-level strings that identify the document type and spec version.
"format": "worldlet",
"format_version": "1.0"
| Field | Required | Description |
|---|---|---|
format |
no | Fixed string "worldlet". Identifies this as a worldlet document. |
format_version |
no | Semver string. Current version is "1.0". |
Both are optional for backwards compatibility but should be included in all new worldlets.
Engine behaviour on import:
- Unknown
format_version— warn and attempt import. - Unknown
formatstring — refuse import. - Both absent — attempt import without warning.
properties GitHub issue
vibecode
{"vibecode": { "section": "properties", "fields": ["temporal"], "purpose": "database_level_metadata_readable_by_any_client_or_agent" }}
Database-level properties that describe the mikobase itself. Any client or agent connecting to or importing the worldlet should read these before interacting with the data.
"properties": {
"temporal": false
}
| Field | Type | Default | Description |
|---|---|---|---|
temporal |
boolean | false |
Whether the importer should save records into version history instead of writing them directly to current state. Worldlets are non-temporal by default; setting true instructs the importer to store each record as a history entry |
temporal tells the importer how to land each record. The default false matches the worldlet format's non-temporal shape (each record carries its current bucket directly, no history block). Set true when the worldlet was exported from a temporal mikobase and the receiving mikobase should preserve that history rather than collapse it into current state.
A small amount of forgiveness for mode mismatches is TBD — exact rules to be filled in once the temporal/non-temporal import paths are settled. See mikobase.md for the full mode rules.
classes GitHub issue
vibecode
{"vibecode": { "section": "classes", "format": "dict_keyed_by_uns_class_name", "methods_as": "fields_with_class_function_and_caspian_key", "see": "class-definition.md" }}
The schema, using the standard class definition format. Each key is a UNS class name; each value is the class definition. All classes defined here are record classes.
Methods are defined as fields with "class": "function" and a "caspian" key containing Caspian source. Multiline strings use literal newlines; leading indentation is stripped by the importer.
"classes": {
"starfleet.com/person": {
"fields": {
"name": {"class": "string", "required": true, "collapse": true},
"birthdate": {"class": "string"},
"species": {"class": "string", "default": "Human"},
"greet": {
"class": "function",
"caspian": "
method &greet
'Hello, I am ' + @name
end
"
}
}
},
"starfleet.com/officer": {
"inherits": "starfleet.com/person",
"fields": {
"rank": {"class": "string", "required": true},
"serial": {"class": "string", "required": true, "unique": true},
"active": {"class": "boolean", "default": true},
"photo": {"class": "puck.uno/dbfile"},
"summary": {
"class": "function",
"caspian": "
method &summary
@rank + ' ' + @name + ' (' + @serial + ')'
end
"
},
"promote": {
"class": "function",
"caspian": "
method &promote(new_rank:)
@rank = new_rank
self
end
"
}
}
},
"starfleet.com/ship": {
"fields": {
"name": {"class": "string", "required": true, "unique": true},
"registry": {"class": "string", "required": true, "unique": true},
"ship_class": {"class": "string"}
},
"join": ["name", "registry"]
}
}
See class-definition.md for the full class definition format.
records GitHub issue
vibecode
{"vibecode": { "section": "records", "format": "dict_keyed_by_uuid", "fields": ["classes", "created_at", "bucket"], "shape": "platter_model_classes_hash_keyed_by_platter_id" }}
A dict of records, keyed by record UUID. Each entry carries the record's classes (its platter stack), creation timestamp, and current bucket. The non-temporal worldlet shape documented here has no separate history block and no per-version entries; for the temporal shape with per-version history, see Puckai.md.
"records": {
"e1b2c3d4-0001-0001-0001-000000000001": {
"classes": {
"p1a2b3c4-0001-0001-0001-000000000001": {
"class": "starfleet.com/officer",
"bucket": {}
}
},
"created_at": "2364-01-01T00:00:00.000Z",
"bucket": {"name": "Picard, Jean-Luc", "rank": "Captain", "serial": "SP-937-215"}
}
}
| Field | Required | Description |
|---|---|---|
classes |
yes | Platter stack: a hash keyed by platter ID, each value {class, bucket} per the platter model. Every record has at least one platter. |
created_at |
no | ISO 8601 timestamp with millisecond precision; record-level metadata, not bucket data. |
bucket |
yes | The record's user-facing field values (those declared by its class definitions). Free-form, no reserved keys. |
Where do values live? For a regular record with a single class platter, the class's declared field values (e.g., name, rank, serial for an officer) live in the top-level bucket. Per-platter buckets are for class-internal state (mix-ins, cross-cutting concerns) — usually empty for ordinary records. Class-definition records are a special case where the platter's bucket holds the definition itself; see class-definition.md.
files GitHub issue
vibecode
{"vibecode": { "section": "files", "format": "dict_keyed_by_file_uuid", "fields": ["sha256", "created_at", "mime.type", "mime.encoding"] }}
A dict of file records, keyed by file UUID. Describes each attached file — its integrity hash, timestamp, and MIME type.
"files": {
"d1e2f3a4-0001-0001-0001-000000000001": {
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"created_at": "2364-01-01T00:00:00.000Z",
"mime": {
"type": "image/png",
"encoding": "base64"
}
}
}
| Field | Description |
|---|---|
sha256 |
SHA-256 hash of the complete file content, for integrity verification |
created_at |
ISO 8601 timestamp |
mime.type |
MIME type of the file |
mime.encoding |
Encoding used for chunk data (e.g. "base64") |
file_chunks GitHub issue
A dict of file chunks, keyed by chunk UUID. A file's binary content is split across one or more chunks. Chunks are assembled in index order to reconstruct the file.
"file_chunks": {
"c1d2e3f4-0001-0001-0001-000000000001": {
"file": "d1e2f3a4-0001-0001-0001-000000000001",
"index": 0,
"last": true,
"data": "base64encodeddata..."
}
}
| Field | Description |
|---|---|
file |
UUID of the parent file record |
index |
Zero-based chunk position |
last |
true on the final chunk — positive confirmation that the file was saved completely. A file with no chunk where last is true is incomplete. |
data |
Chunk content, encoded per the file's mime.encoding |
Import Rules GitHub issue
vibecode
{"vibecode": { "section": "import_rules", "covers": ["uuid_constraints", "conflict_policy", "reference_encoding", "class_field", "validation", "atomicity"], "conflict_policy_summary": "incoming_record_with_existing_uuid_overwrites; stricter_policies_are_application_concerns", "atomicity_summary": "validation_errors_abort_entire_import; no_partial_writes", "validation_summary": "every_record_has_class_and_bucket; class_must_be_known_to_importer; created_at_iso_8601_millisecond_precision" }}
UUID constraints GitHub issue
Keys in records, files, and file_chunks are conventionally UUID v4 strings, but Mikobase requires only uniqueness — not a specific format and not cryptographic soundness. UUIDs are used for collision avoidance, not security. Any unique string is accepted today; the policy may tighten later. See mikobase.md § Record identity.
Caspian code generating record IDs should use %utils.random.uuid, which returns a cryptographically secure UUID v4 sourced from the OS CSPRNG via libsodium.
Conflict policy GitHub issue
A worldlet is a non-temporal mikobase serialized to JSON. Importing records is just writing them — when an incoming record has the same UUID as one already in the target, the incoming record overwrites the existing one. The same rule applies to files and file_chunks entries.
Whether overwrites are desirable is an application concern, not something the worldlet primitive should decide. Apps that want stricter behavior (skip-on-conflict, abort-on-conflict, prompt for review, etc.) can wrap import in their own check before calling.
Reference encoding GitHub issue
Reference fields in bucket are plain UUID strings. The class definition declares the field type — a field with class puck.uno/reference or puck.uno/dbfile tells the engine the value is a reference. No special wrapper syntax is used in the bucket itself.
The class field inside platter records GitHub issue
In all Puck-compliant platter records, the class field identifies the class for that platter. This applies to Q0 queries, record entries' class definitions, and any other Puck-level objects.
Bucket objects (top-level or platter-internal) are not Puck-compliant. The class key has no special meaning inside a bucket and may be used freely as an application field.
Validation GitHub issue
The importer validates the following before writing anything:
- All record entries have a
classeshash and abucket. - Every record's
classeshash contains at least one platter entry. - All
classvalues inside platter records are either built-in classes, defined in this worldlet'sclassessection, or already present in the target mikobase. - All
filevalues infile_chunksreference a UUID present infiles. - The target mikobase is non-temporal.
Atomicity GitHub issue
Import is all-or-nothing. If any validation error or conflict error occurs, nothing is written to the target mikobase. Partial imports do not happen.
Minimal Valid Example GitHub issue
vibecode
{"vibecode": { "section": "minimal_valid_example", "shows": "smallest_complete_worldlet_that_imports_without_error", "omits": ["meta", "properties", "classes", "files", "file_chunks"], "defaults_relied_on": { "record_classes": "single platter of class puck.uno/record (built_in) when classes is omitted", "classes_section": "not_needed_when_only_built_in_classes_used" } }}
The smallest possible worldlet — one record, no schema, no files:
{
"format": "worldlet",
"format_version": "1.0",
"records": {
"e1b2c3d4-0001-0001-0001-000000000001": {
"bucket": {"note": "hello"}
}
}
}
The classes field on the record is omitted; the importer applies the default — a single platter of class puck.uno/record, with an engine-generated platter ID. The top-level worldlet classes section is also omitted because puck.uno/record is a built-in class so no schema is needed.
Complete Example GitHub issue
vibecode
{"vibecode": { "section": "complete_example", "shows": "every_top_level_section_with_realistic_starfleet_data", "includes": ["meta", "properties", "classes_with_one_class", "records_with_one_record", "files_with_one_file", "file_chunks_with_one_chunk"], "purpose": "reference_template_for_implementers_writing_producers_or_consumers" }}
{
"format": "worldlet",
"format_version": "1.0",
"meta": {
"name": "Starfleet Personnel",
"author": "starfleet.com",
"version": "1.0.0",
"description": "Personnel records for Starfleet officers and ships.",
"created_at": "2364-01-01T00:00:00.000Z"
},
"properties": {
"temporal": false
},
"classes": {
"starfleet.com/person": {
"fields": {
"name": {"class": "string", "required": true, "collapse": true},
"birthdate": {"class": "string"},
"species": {"class": "string", "default": "Human"},
"greet": {
"class": "function",
"caspian": "
method &greet
'Hello, I am ' + @name
end
"
}
}
},
"starfleet.com/officer": {
"inherits": "starfleet.com/person",
"fields": {
"rank": {"class": "string", "required": true},
"serial": {"class": "string", "required": true, "unique": true},
"active": {"class": "boolean", "default": true},
"photo": {"class": "puck.uno/dbfile"},
"summary": {
"class": "function",
"caspian": "
method &summary
@rank + ' ' + @name + ' (' + @serial + ')'
end
"
},
"promote": {
"class": "function",
"caspian": "
method &promote(new_rank:)
@rank = new_rank
self
end
"
}
}
},
"starfleet.com/ship": {
"fields": {
"name": {"class": "string", "required": true, "unique": true},
"registry": {"class": "string", "required": true, "unique": true},
"ship_class": {"class": "string"}
},
"join": ["name", "registry"]
}
},
"records": {
"e1b2c3d4-0001-0001-0001-000000000001": {
"classes": {
"p1a2b3c4-0001-0001-0001-000000000001": {"class": "starfleet.com/officer", "bucket": {}}
},
"created_at": "2364-01-01T00:00:00.000Z",
"bucket": {"name": "Picard, Jean-Luc", "rank": "Captain", "serial": "SP-937-215"}
},
"e1b2c3d4-0002-0002-0002-000000000002": {
"classes": {
"p1a2b3c4-0002-0002-0002-000000000002": {"class": "starfleet.com/officer", "bucket": {}}
},
"created_at": "2364-01-01T00:00:00.000Z",
"bucket": {"name": "Riker, William", "rank": "Captain", "serial": "SC-231-427"}
},
"e1b2c3d4-0003-0003-0003-000000000003": {
"classes": {
"p1a2b3c4-0003-0003-0003-000000000003": {"class": "starfleet.com/ship", "bucket": {}}
},
"created_at": "2364-01-01T00:00:00.000Z",
"bucket": {"name": "USS Enterprise", "registry": "NCC-1701-D", "ship_class": "Galaxy"}
},
"e1b2c3d4-0004-0004-0004-000000000004": {
"classes": {
"p1a2b3c4-0004-0004-0004-000000000004": {"class": "starfleet.com/officer", "bucket": {}}
},
"created_at": "2364-01-01T00:00:00.000Z",
"bucket": {"name": "Data", "rank": "Lieutenant Commander", "serial": "SA-789-012", "photo": "d1e2f3a4-0001-0001-0001-000000000001"}
}
},
"files": {
"d1e2f3a4-0001-0001-0001-000000000001": {
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"created_at": "2364-01-01T00:00:00.000Z",
"mime": {
"type": "image/png",
"encoding": "base64"
}
}
},
"file_chunks": {
"c1d2e3f4-0001-0001-0001-000000000001": {
"file": "d1e2f3a4-0001-0001-0001-000000000001",
"index": 0,
"last": true,
"data": "base64encodeddata..."
}
}
}