| module | core/play | |||||
|---|---|---|---|---|---|---|
| repo | core/play | |||||
| lang | multi | |||||
| tier | consumer | |||||
| depends |
|
|||||
| tags |
|
core playruns preserved software from deterministic STIM bundles. Games are the demo. Legacy enterprise is the product.
Module: dappco.re/go/play
Repository: core/play
Status: Draft, spec-first
Primary dependency: core/app supplies the manifest and boot contract
Core Play is the runtime for preserved software packaged as STIM bundles. A STIM bundle combines:
- the original artefact
- the runtime needed to execute it
- the metadata needed to verify, launch, and preserve it
The immediate product shape is a games runtime. The broader product shape is a general preservation and controlled execution system for legacy software.
Core Play is not a general-purpose application framework. It sits on top of the Core stack and consumes existing runtime primitives.
core/appdefines manifest discovery and boot flowcore/guiowns windows, rendering surfaces, and platform shell concernscore/go/buildproduces deterministic bundle artefactscore/cliexposes command registration and command routing- Shield-style verification surfaces provide integrity, SBOM, and threat checks
- Run preserved software from a deterministic, verifiable bundle
- Separate the artefact from the runtime engine cleanly
- Keep execution sandboxed and auditable
- Make bundle verification possible without launch
- Support both curated catalogue distribution and local BYOROM workflows
- Reuse the same bundle contract for games and enterprise preservation
- Writing emulator engines from scratch
- Replacing
core/apporcore/gui - Doing per-title game porting work inside this module
- Defining commercial rights for individual games inside the runtime itself
- Solving cloud streaming as a requirement for local playback
STIM means Sandboxed Temporal Isolation Module.
A STIM bundle is a self-describing directory or archive that preserves:
- the original software artefact
- the engine or runner required to execute it
- the verification chain needed to prove integrity
The original software payload:
- ROM
- binary
- installer
- data files
- application package
The runtime used to execute the artefact:
- emulator core
- compatibility layer
- native runner
Examples include DOSBox, DOSBox-X, ScummVM, RetroArch-based adapters, or a native wrapper.
The on-disk shape used by core play. A bundle can be:
- a directory in development
- a deterministic archive for distribution
A known index of playable or installable bundles, typically rights-cleared, curated, and pre-verified.
Bring Your Own ROM or, more generally, Bring Your Own Artefact. The user supplies the original software. Core Play supplies verification, packaging, and runtime selection where possible.
Core Play has three jobs at once:
- preserve software
- run software safely
- prove the Core distribution pipeline on a simpler product than CoreLEM
The games-facing product is important because it is visible, demoable, and emotionally legible. The same machinery also fits long-tail enterprise cases:
- preserved COBOL workloads
- old Win32 operational tools
- legacy monitoring agents
- internal software that must survive platform churn
This RFC therefore treats games as the initial catalogue, not as the only valid content type.
Every STIM bundle has a deterministic and inspectable structure.
mega-lo-mania/
├── manifest.yaml
├── rom/
│ └── MegaLoMania.zip
├── emulator.yaml
├── sbom.json
└── checksums.sha256
The directory name is the bundle code and defaults to the runnable name.
| File | Required | Purpose |
|---|---|---|
manifest.yaml |
Yes | Identity, artefact metadata, runtime binding, permissions |
rom/ |
Yes | Original artefact payload |
emulator.yaml |
Yes | Engine-specific launch configuration |
sbom.json |
Yes | CycloneDX or equivalent bundle inventory |
checksums.sha256 |
Yes | Hash chain for deterministic verification |
| File | Purpose |
|---|---|
cover.png |
Catalogue artwork |
licence.txt |
Rights or redistribution text |
notes.md |
Preservation notes and provenance |
patches/ |
Optional compatibility patches declared in the manifest |
saves/seed/ |
Optional starter save state or test fixtures |
The manifest is the bundle contract. It describes what the bundle is, what it contains, what engine it expects, what permissions it needs, and how integrity is proven.
format_version: stim-v1
name: mega-lo-mania
title: "Mega lo Mania"
author: "Sensible Software"
year: 1991
platform: sega-genesis
genre: strategy
licence: freeware
artefact:
path: rom/MegaLoMania.zip
sha256: "9f0f..."
size: 554192
media_type: application/zip
source: "Rights-cleared redistribution"
runtime:
engine: retroarch
profile: genesis
config: emulator.yaml
entrypoint: rom/MegaLoMania.zip
acceleration: auto
filter: nearest
verification:
chain: checksums.sha256
sbom: sbom.json
deterministic: true
permissions:
network: false
microphone: false
filesystem:
read:
- rom/
write:
- saves/
- screenshots/
resources:
cpu_percent: 75
memory_bytes: 268435456
save:
path: saves/
screenshots: screenshots/
distribution:
mode: catalogue
byorom: false| Field | Required | Meaning |
|---|---|---|
format_version |
Yes | STIM manifest schema version |
name |
Yes | Stable machine identifier |
title |
Yes | Human-readable title |
author |
No | Original developer or studio |
year |
No | Original release year |
platform |
Yes | Target platform of the artefact |
genre |
No | Catalogue metadata |
licence |
Yes | Rights model for bundle distribution |
artefact |
Yes | Original payload metadata |
runtime |
Yes | Engine binding and launch entry |
runtime.acceleration |
No | Preferred acceleration policy: off, auto, or required |
runtime.filter |
No | Preferred display filter such as none, nearest, bilinear, scanline, or crt |
verification |
Yes | Integrity chain declaration |
permissions |
Yes | Sandbox and runtime capability declaration |
resources |
No | CPU and memory ceilings for sandboxed execution |
save |
No | Save-state and screenshot layout |
distribution |
No | Delivery-mode hints |
The current supported manifest format is stim-v1. Manifests without
format_version are treated as legacy RFC-era bundles and are normalised to
stim-v1 at load time. Unknown future format versions must be rejected rather
than silently interpreted under the wrong schema.
emulator.yaml carries engine-specific launch details which do not belong in
the top-level manifest.
engine: retroarch
profile: genesis
input:
type: gamepad
mapping: default-genesis
display:
scale: 3x
acceleration: auto
filter: nearest
aspect: original
audio:
enabled: true
sample_rate: 44100
performance:
rewind: false
fast_forward: truechecksums.sha256 records hashes for every material file in the bundle.
At minimum:
manifest.yamlemulator.yaml- every file in
rom/ sbom.json- any declared patch or auxiliary content
The hash list must be stable under deterministic rebuilds.
The verification chain is treated as a coverage contract:
- paths must be canonical relative bundle paths
- duplicate path entries are invalid
- required files must appear in the chain
- material files not recorded in the chain are reported as unverified content
- the chain file itself is exempt from self-hashing
sbom.json represents the bundle inventory, not only the engine binary.
It should include:
- artefact payload
- engine package or engine identifier
- launch configuration
- applied patches
- build provenance where available
CycloneDX is the preferred initial format.
Core Play is a CoreCommand and should map cleanly to CLI, HTTP, MCP, and localisation surfaces.
| Surface | Path | Purpose |
|---|---|---|
| CLI | core play {name} |
Run a bundle |
| CLI | core play/list |
List available bundles |
| CLI | core play/verify {name} |
Verify without launching |
| CLI | core play/bundle |
Create a bundle |
| HTTP | GET /play/{name} |
Launch or request launch |
| MCP | play |
Agent-facing bundle interaction |
| i18n | play.* |
User-facing strings |
core play resolves bundles in the following order:
- current working directory if
manifest.yamlexists - named child directory in a configured catalogue root
- installed local bundle index
- explicit path argument if provided
Examples:
core play
core play mega-lo-mania
core play ./bundles/mega-lo-mania
core play/list
core play/verify mega-lo-maniafunc Register(c *core.Core) {
c.Command("play", core.Command{
Description: "Run preserved software in a STIM bundle",
Action: cmdPlay,
})
c.Command("play/list", core.Command{
Description: "List available STIM bundles",
Action: cmdPlayList,
})
c.Command("play/verify", core.Command{
Description: "Verify a bundle without running it",
Action: cmdPlayVerify,
})
c.Command("play/bundle", core.Command{
Description: "Create a deterministic STIM bundle",
Action: cmdPlayBundle,
})
}| Command | Success | Failure |
|---|---|---|
play |
Launches or hands off to launcher | Verification, resolution, or engine error |
play/list |
Returns catalogue entries | Index error |
play/verify |
Reports verified status | Hash, manifest, or SBOM mismatch |
play/bundle |
Produces deterministic bundle | Invalid inputs or non-deterministic output |
The runtime should follow a strict boot order:
- discover bundle
- load
manifest.yaml - verify hash chain and bundle structure
- resolve engine adapter
- prepare sandbox
- mount save-state directories
- launch engine with declared config
- capture outcome, logs, and optional screenshots
Engine support is provided through adapters, not hard-coded branches.
type Engine interface {
Name() string
Platforms() []string
Verify() error
Launch(bundle Bundle, cfg Config) error
}Registration should use build tags where that keeps platform-specific or licence-sensitive adapters separate.
//go:build engine_dosbox
func init() {
play.RegisterEngine(&DOSBoxEngine{})
}Initial adapter coverage:
| Engine | Platforms | Notes |
|---|---|---|
dosbox |
DOS | Simple DOS artefact launch |
dosbox-x |
DOS, PC-98, Windows 3.x, Windows 9x | Machine/profile-aware boot planning |
retroarch |
Genesis, SNES, NES, Game Boy families | Libretro core selection through runtime.profile |
scummvm |
ScummVM and point-and-click bundles | Game ID supplied through runtime.profile |
mame |
Arcade, Neo Geo | Driver/profile launch with ROM directory isolation |
vice |
C64, C128, VIC-20 | Autostart launch for Commodore disk/tape artefacts |
fuse |
ZX Spectrum 48K/128K | Machine profile mapped to FUSE machine selection |
snes9x |
SNES, Super Nintendo | Standalone SNES runner where RetroArch is not desired |
Engine selection should be explicit first, heuristic second.
Order:
- manifest
runtime.engine - manifest
runtime.profile - platform match
- configured default adapter
If no valid adapter exists, verification may still succeed, but launch fails with a precise engine-resolution error.
Default runtime policy:
- no outbound network
- no writes outside the declared save-state root
- no arbitrary process spawning from the bundle
- resource ceilings set from manifest defaults or platform policy
- engine binaries must pass integrity checks before launch
Manifest permissions can narrow access further. They should not silently widen host access beyond platform policy.
Before launch, the resolved engine plan must be checked against the prepared
sandbox policy. A launch plan that requests network access, read paths, runtime
config access, resource ceilings, or write paths outside the manifest-derived
allowlist is rejected before process start. Required runtime files such as the
artefact, entrypoint, and emulator.yaml are folded into the effective read
allowlist so adapters cannot rely on undeclared bundle reads.
Filesystem write declarations are clamped to the save-state and screenshot roots. The manifest may narrow writes to a child path of those roots, but it must not widen host write access by declaring arbitrary bundle directories.
~/.core/play/
├── mega-lo-mania/
│ ├── saves/
│ ├── screenshots/
│ └── session.log
└── command-and-conquer/
├── saves/
└── screenshots/
The runtime owns these directories. Bundle content should be treated as read-only after verification.
The runtime should capture:
- engine selected
- verification result
- launch duration
- exit code or failure class
- save-state path
- optional screenshot artefacts for catalogue QA
Every STIM bundle is also a verification subject.
| Surface | Purpose |
|---|---|
| SBOM | Describe bundle inventory and provenance |
| Code | Verify engine package or adapter integrity |
| Content | Verify original artefact hash |
| Threat | Detect unexpected payloads or tampering |
core play/verify should confirm:
- required files exist
- manifest parses and is internally coherent
- every declared file hash matches
- the SBOM file exists and matches declared location
- the engine named by the manifest is known or marked unresolved
- ZIP artefacts reject unsafe paths, executable/script payloads, excessive expansion, oversized entries, oversized aggregate expansion, and excessive path nesting before launch
The same inputs should produce the same bundle outputs, including:
- file names
- file ordering
- timestamps normalised where supported
- checksum file contents
- archive layout
This matters for preservation and for supply-chain trust.
Verification failures should be categorised clearly:
bundle/not-foundbundle/invalid-structuremanifest/invalidhash/mismatchsbom/missingthreat/entry-sizethreat/path-depthengine/unavailablesandbox/policy-denied
These codes should be shared across CLI, HTTP, and MCP where practical.
core play/bundle turns a raw artefact into a runnable STIM bundle.
Typical inputs:
- bundle name
- title and metadata
- source artefact
- platform
- engine
- runtime profile
- rights and redistribution mode
Example:
core play/bundle \
--name mega-lo-mania \
--title "Mega lo Mania" \
--rom MegaLoMania.zip \
--platform sega-genesis \
--engine retroarch \
--profile genesis \
--licence freewareThe command should produce:
manifest.yamlemulator.yamlchecksums.sha256sbom.json- deterministic archive output if requested
- inspect input artefact
- assign runtime adapter
- emit manifest and runtime config
- generate checksum chain
- generate SBOM
- verify the just-built bundle
- optionally archive deterministically
For BYOROM or enterprise ingestion, bundle creation may omit any curated catalogue metadata not required for execution.
That still does not relax:
- checksum generation
- manifest integrity
- sandbox declaration
- engine resolution
Core Play should support multiple distribution shapes without requiring the runtime contract to fork.
- self-compiled player
- user-supplied artefacts
- no remote entitlement requirement
- full local verification path
This is the baseline preservation mode.
- rights-cleared bundles
- prebuilt verification metadata
- artwork and catalogue metadata
- consistent engine packaging
This is the likely default consumer experience.
Core Play is also positioned as a pipeline proof before CoreLEM:
- simpler review surface than a full AI or compute-heavy product
- validates CoreGUI rendering, input, and packaging path
- exercises build, test, archive, and signing flow
This section is a product proposal, not a platform guarantee. Any platform distribution plan must be revalidated against current policy and current rights.
Proposed commercial tiers:
| Tier | Shape | Notes |
|---|---|---|
| 1 | Platform-subsidy tier | Free to eligible subscribers if commercial terms exist |
| 2 | Direct paid tier | Monthly, yearly, or lifetime entitlement |
| 3 | Free source tier | Self-compiled, BYOROM, no catalogue entitlement |
Some catalogue bundles may use a protected artefact format, such as a .stim
payload delivered separately from the open player.
If used, the design constraints are:
- decryption should occur in memory
- protected content should not be required for free-tier BYOROM support
- entitlement checks must be separable from bundle execution logic
- the open runtime must remain functional without protected catalogue assets
This keeps preservation mode intact while allowing a commercial catalogue layer.
| Title | Year | Platform | Engine | Rights model |
|---|---|---|---|---|
| Mega lo Mania | 1991 | Sega Genesis | RetroArch profile | Freeware or licensed |
| Command & Conquer | 1995 | DOS | DOSBox | Rights-cleared freeware |
| Prince of Persia | 1989 | DOS | DOSBox | Open-source or authorised distribution |
| Cave Story | 2004 | Native | Native runner | Freeware |
| Tyrian | 1995 | DOS | DOSBox | Freeware |
| Beneath a Steel Sky | 1994 | ScummVM | ScummVM | Freeware |
These titles are examples for planning. Final inclusion depends on current rights and packaging work.
The same bundle contract can preserve:
| Software type | Example use |
|---|---|
| Legacy COBOL workload | Bank migration bridge |
| Old Win32 internal tool | Operational continuity during replacement |
| Deprecated monitoring agent | Sandboxed stopgap while migration completes |
Enterprise value comes from preservation, verification, and controlled execution, not from the games catalogue itself.
| Phase | Outcome |
|---|---|
| 1 | Manifest parser and bundle validator |
| 2 | play, play/list, and play/verify command registration |
| 3 | Engine registry and adapter contract |
| 4 | First engine adapter, likely DOSBox |
| 5 | Save-state layout and sandbox policy |
| 6 | play/bundle creation flow |
| 7 | Shield-aligned verification and SBOM generation |
| 8 | Catalogue index and launch candidates |
| 9 | Additional adapter coverage, including DOSBox-X for PC-98 and Windows-era images |
| 10 | Optional protected asset and entitlement profile |
The first milestone worth shipping is:
- directory bundle validation
- one runnable engine
- one known-good title
- local BYOROM support
- Should
emulator.yamlremain engine-specific, or be renamed to a more neutralruntime.yamllater? - Does the runtime ever need per-bundle signed manifests beyond checksum verification?
- Which engine adapters ship by default versus behind build tags?
- Is protected catalogue delivery a separate module, or an optional extension of
core/play? - How much of the save-state format should be normalised across engines?
- Should enterprise bundles reuse the same
rom/directory name, or move to a more generalartefact/path?
These questions do not block the initial implementation, but they should remain visible while the first runnable slice lands.
- 2026-04-27: Pass 8 clamped sandbox write permissions to save-state and screenshot roots so manifests can narrow, but not expand, host write access.
- 2026-04-27: Pass 7 added manifest-declared CPU and memory resource ceilings to sandbox policy and launch-plan validation.
- 2026-04-27: Pass 5 added explicit STIM manifest format versioning with a legacy migration path, and hardened Shield threat scanning against oversized ZIP entries, oversized aggregate archive expansion, and deeply nested artefact paths.
- 2026-04-27: Pass 4 added MAME, VICE, FUSE, and standalone Snes9x adapter scaffolds, tightened canonical bundle path handling, and expanded sandbox read/write allowlist enforcement around runtime config access.
- 2026-04-27: Pass 3 tightened checksum-chain coverage semantics, added DOSBox-X adapter planning, enforced launch-plan sandbox boundaries, and pinned parser/catalogue verification tests.
- 2026-04-08: Reworked into a cleaner draft with goals, bundle contract, runtime architecture, verification model, distribution profiles, delivery phases, and open questions.
- 2026-04-01: Initial notes covering STIM bundles, engine registry, verification chain, and catalogue direction.