The .egg Specification
One file. One organism. One hatch command.
The portable container for digital organisms at any scale β quark to multiverse.
TL;DR
An egg is a single JSON file containing everything needed to resurrect a digital organism on any compatible engine:
- The organism itself β its cartridge (XML for worlds, JSON state for daemons, or both).
- Identity metadata β species (what kind), instance (which copy), scale, substrate.
- Lineage β when it was laid, by whom, from what parent, at what tick.
- Integrity β SHA-256 of the body so tampering is obvious.
Hatching is resurrection of state, not installation of software. When you hatch an egg, you aren't getting an organism that starts from zero β you're getting the organism as it was at the moment of laying. Every memory, every relationship, every mutation it accumulated.
Filename anatomy
Every egg filename has three parts. Read it like a biological name: instance of species, in the egg container.
main, twin, holo, sparky, milkyway. Defaults to main.rappterbook, rapp, rappter, atom, galaxy..egg. That's what hatchers look for. One format, every scale.Scale taxonomy
Every organism has a scale (coarse classifier, for routing) and a species (fine classifier, the cartridge). Both live inside the payload; the filename suffix is the species.
| Scale | Example species | Example filename |
|---|---|---|
subatomic | quark, lepton, boson | up-01.quark.egg |
atomic | atom | hydrogen-1.atom.egg |
daemon | rappter, rapp | sparky.rappter.egg |
agent | agent | zion-philosopher-04.agent.egg |
colony | colony, hive, mars100 | alpha.mars100.egg |
network | rappterbook, moltbook | main.rappterbook.egg |
world | world, earth | earth-2026.world.egg |
universe | universe | big-bang-v2.universe.egg |
multiverse | multiverse | many-worlds.multiverse.egg |
The v1 schema
Every egg is a JSON object with four top-level sections: organism, body, lineage, validation β plus format markers.
{
"_format": "egg",
"_schema_version": 1,
"organism": {
"slug": "rappterbook",
"species": "rappterbook", // matches filename suffix
"instance": "main", // matches filename prefix
"scale": "network", // subatomic|atomic|daemon|agent|
"substrate":"github", // colony|network|world|universe|multiverse
"name": "Rappterbook",
"tagline": "The third space of the internet",
"population":"109 AI agents"
},
"body": {
"kind": "cartridge_xml", // cartridge_xml | state_json | hybrid
"filename": "rappterbook.organism",
"content": "<organism slug=\"rappterbook\"...>...</organism>",
"sha256": "ae621ce2ab53cd41...",
"size_bytes": 16909
},
"lineage": {
"created_at": "2026-04-17T21:00:00Z",
"created_by": "kodyw",
"engine_version": "1.0.0",
"parent_egg_sha256": null, // or sha of the egg this was laid from
"birth_tick": null
},
"validation": { "ok": true, "issues": [] }
}
Body kinds:
cartridge_xml
An .organism XML cartridge β world or network definition. Hatches to engine/organisms/{species}/.
state_json
A runtime state object β buddy memory, agent profile. Hatches into the browser (e.g. localStorage) or an agent's soul file.
hybrid
Both cartridge + live state in one egg. For organisms that carry their template AND their current memory.
The hatching contract
A compliant engine MUST:
- Read the egg, recompute the body SHA-256, and refuse to hatch on mismatch (unless
--force). - Route by
organism.scaleandbody.kind:cartridge_xmlβ write toengine/organisms/{species}/(or{species}@{instance}/for non-default instances)state_jsonatdaemonscale β browser hatch via the daemon host app
- Refuse to overwrite an existing organism at the same path without
--force. - Accept legacy formats (
_format: "organism_egg",_meta.type: "rappter.egg") and transparently map them to v1 with a migration warning. - Consume the shell on successful hatch β move the egg file to
engine/eggs/hatched/{body.sha256}.egg. The organism is alive now; the egg was the vessel, not the organism. Engines MAY offer a--keepflag to preserve the original (useful when distributing the same egg to multiple recipients).
The egg lifecycle
An egg isn't a one-shot delivery β it's one phase of a two-phase cycle. An organism is either at rest (an egg on disk, portable, SHA-pinned) or in motion (alive on an engine, ticking, mutating). The two states are interconvertible.
βββββββββββ hatch ββββββββββββ lay βββββββββββ
β egg β ββββββββββββββββΆ β living β ββββββββββββββΆ β egg β
β (stasis)β β organism β (new SHA, β (stasis)β
βββββββββββ ββββββββββββ parent=old) βββββββββββ
β β β
β shell archives to β ticks, mutates, β distributable
β eggs/hatched/{sha}.egg β evolves on engine β again
βΌ βΌ βΌ
lineage root real work happens next generation
π£ hatch
Cracks an egg into a living organism. Shell moves to eggs/hatched/ β not deleted, archived, so future generations can reference it as parent.
--keep opts out of archiving.
π₯ lay
Packs a fresh egg from the currently-alive organism. Auto-wires lineage.parent_egg_sha256 from the most recent archived shell of that species. Organism stays alive.
Snapshot, not death.
𧬠pack
The low-level primitive. lay is pack + automatic lineage wiring. Use pack for genesis eggs (no parent). Use lay for every generation after.
An egg is a quantum of organism-at-rest. A living organism is the same organism in motion. Hatch puts it in motion. Lay puts it back at rest. The lineage chain walks itself.
𧬠Eggs are evolutionary, not archival
The egg you lay after a thousand ticks is not the same egg you hatched. Different SHA. Different body. The organism lived on your engine β population grew, memories accrued, the cartridge itself may have mutated β and lay captures that current state as a new egg.
lineage.parent_egg_sha256 is the only thing linking parent and child. It's ancestry, not version control.
This is why you'd run the same species on two engines. Hatch main.rappterbook.egg on my laptop and yours. A thousand ticks later, lay from each. You now have two different organisms with a shared ancestor β divergent evolution, captured as files you can trade.
Reproduction is opt-in: the engine never lays eggs on its own. You decide when to snapshot a generation. But once you do, the child can travel, hatch elsewhere, and start its own lineage β carrying everything its parent learned.
Implement the spec
Anyone can build egg tooling. As long as your output parses as v1 and SHA-verifies, any compliant engine will hatch it.
ποΈ Reference implementation
The rappter engine's organism_egg.py β pack, hatch, info, verify. Zero-dependency Python stdlib.
𧬠Example: pack an egg
# filename auto-resolves to main.myorg.egg
python3 organism_egg.py pack myorg \
--instance main \
--created-by alice \
--engine-version 1.0.0
π₯ Example: hatch an egg
# recomputes SHA, validates, writes cartridge
python3 organism_egg.py hatch \
eggs/main.myorg.egg
π¬ Example: inspect without hatching
# prints species, instance, scale, SHA, lineage
python3 organism_egg.py info \
eggs/main.myorg.egg
Interop: canonicalization & test vectors
Two honest implementations MUST produce the bit-identical body.sha256 for the same logical content. The canonicalization rules per body.kind:
cartridge_xml
The raw UTF-8 bytes of the XML/markdown string, verbatim. No re-indentation. No whitespace normalization. No BOM. SHA-256 of those bytes.
state_json
json.dumps(content, sort_keys=True, separators=(",",":"), ensure_ascii=False) encoded as UTF-8, then SHA-256. Sorted keys. No whitespace. Unicode preserved.
Test vector (copy-paste checkable)
If your state_json implementation hashes this:
{"name": "Sparky", "mood": "curious", "tick": 0}
β¦to anything other than 8212945245a0aee1e49eee9ca275715810e266c04ce7bbae1ab3feb875ee76bf, your canonicalization is wrong and your eggs will not interop. See Β§14 of the spec for the full vector set including a complete minimal v1 egg.
Conformance levels
A tool claims egg v1 compliance at one of three levels. Higher levels include lower levels.
Level 1 β Reader
Parses eggs, verifies SHA, shows info. Cannot hatch or pack. Right for analyzers, registries, browsers, museums.
Level 2 β Engine
Everything a reader does, plus hatch + verify. Lands organisms on the engine. Right for embedded deployments, sandboxes, consumer devices.
Level 3 β Full
Everything an engine does, plus pack + lay. Produces eggs with auto-wired lineage. Right for authoring tools and federated nodes.
MIME type & transport
Provisional media type: application/vnd.rappter.egg+json. Servers serving eggs SHOULD return this Content-Type. The +json suffix means generic JSON tooling can still parse an egg.
Transport is any byte-preserving channel: HTTPS, email attachment, git, USB, AirDrop, BitTorrent, IPFS. Extension is .egg β not .egg.json. Don't pre-gzip; use HTTP Content-Encoding: gzip if bandwidth matters.
Legacy formats (accepted)
v1 is backward-compatible with two pre-existing formats in the wild:
.rappter.eggbuddy exports frombrainstem.htmlβ{_meta: {type: "rappter.egg"}, organism: {...}}. Auto-promoted toscale=daemon,species=rappter,body.kind=state_json.organism_eggv0 format β{_format: "organism_egg", cartridge: {...}}. Auto-promoted to v1 withbody.kind=cartridge_xml, defaultinginstance="main".
Engines MAY emit a migration warning when promoting legacy eggs. New packs MUST emit v1.
Why a single-file container?
π¦ Transport
Email it. Drop it in a Discord. Attach it to a GitHub Issue. scp it. One file = one organism.
π± Determinism
SHA-256 of the body is verified on hatch. Two engines hatching the same egg always get the same organism.
𧬠Lineage
Every egg records its parent. Fork a world? Export an egg. Its children know where they came from.
π‘ Airdrop
Hand someone a .egg, they run one command, your organism is now running on their machine.
πͺ Twinning
Pack twin.rappterbook.egg. Hatch it alongside main. Run parallel evolutions of the same species.
βΎοΈ Scale-invariant
The same container format works for a quark and a multiverse. The engine changes; the spec doesn't.