Last updated: 2026-03-18
This guide is the complete pre-cleanup baseline for creating installer-managed non-core apps.
Use this when you want:
- A new app tab payload.
- A repeat-safe install path.
- A reversible uninstall path.
- A contract-first package that survives cleanup/refactor transitions.
Required artifacts:
- App HTML payload file:
project/client/apps/non-core/core/tab-<appId>.html
- Installer contract file:
project/server/contracts/installer-<appId>.contract.example.json
- Install actions in contract:
- non-core loader registration
- window app registry registration
- app category map registration
- Uninstall actions in contract:
- one remove action per installed entry, matched by the same
entryId
- one remove action per installed entry, matched by the same
Required naming rules:
appIdis the single source id across all surfaces.appIdmust match exactly in:- contract
appId - non-core loader
tabId - window app registry
tab - category map key
- contract
- Use lower-case id format only (examples:
helloworld,note-pad). - Each action must have a stable
entryIdstring.
Recommended entryId format:
<appId>-loader-001<appId>-window-001<appId>-category-001
Installer-safe insertion regions use exact marker boundaries.
Empty safe slot shape:
//Open Next json entry id
//Close "Installed entry shape:
//Open Next json entry id
//JsonEntryId: "<entryId>"
<payload line(s)>
//Close "
//Open Next json entry id
//Close "Notes:
- The installer matches only exact open + blank + close regions.
- The installer writes
JsonEntryIdmetadata for uninstall targeting. - The installer preserves a new empty slot after every insert.
Minimum payload requirements:
- File lives under
project/client/apps/non-core/core/. - Top-level tab container id must be
tab-<appId>. - Avoid global side effects on repeated tab loads.
- Keep script logic self-contained for optional app loading.
Scope note (important):
- Installer baseline manages registration wiring and uninstall of installer-managed entries.
- Installer can now manage payload file lifecycle through contract actions:
create-file(install)delete-file(uninstall)
- Installer still does not patch arbitrary HTML internals using marker boundaries; it manages payload files as whole-file create/delete units.
- Package authors can provide payload content directly (
payload) or via template source (templatePath) in the install contract.
Example skeleton:
<div class="tab-content" id="tab-myapp">
<section class="card">
<div class="card-hd"><h3>My App</h3></div>
<div>App content</div>
</section>
</div>
<script>
(function () {
if (window.__myAppInit) return;
window.__myAppInit = true;
// app code
})();
</script>Contract file path:
project/server/contracts/installer-<appId>.contract.example.json
Required top-level fields:
contractVersionappIdinstallActionsuninstallActionsanchorsmarkerBoundaryfingerprintmismatchPolicytransactionPolicyloggingPolicy
Supported action types:
insertandremovefor marker-managed registration wiring.create-fileanddelete-filefor payload file lifecycle.
Policy requirements:
markerBoundary.openMarkeris//Open Next json entry idmarkerBoundary.closeMarkeris//Close "markerBoundary.requireBlankLineBetweenistruetransactionPolicy.onMissingMarkerBoundaryisauto-rollback-errortransactionPolicy.modeisall-or-nothingloggingPolicy.logEntryIdistrueloggingPolicy.logWrittenBlockistrueloggingPolicy.logCloseMarkeristrueloggingPolicy.logJsonEntryIdistrue
Reference schema:
project/server/contracts/installer-uninstaller-contract.schema.json
Reference example:
project/server/contracts/installer-hello-world.contract.example.json
Required conventions:
- Non-core loader registration includes:
tabId,enabled,path,label,icon,navTarget
- Use
navTarget: '#navOptionalAppsHost'for optional/non-core apps. - Window app registration includes:
tab,label,icon,accent,w,h
- Category map key must be one of:
core,browse,tools,mind,journal,appearance,system
Icon conventions:
- Non-core loader icon uses lightweight glyph (emoji or short symbol).
- Window app icon uses inline SVG string for shell/taskbar consistency.
Run from project/.
Install app from contract:
node server/tools/installer-cli.js install --contract server/contracts/installer-<appId>.contract.example.json --root . --log server/contracts/installer-<appId>.install.log.jsonInstall supports payload-file creation actions:
create-filewithpayload(inline file content)create-filewithtemplatePath(copy from stable template source)
Uninstall app from contract:
node server/tools/installer-cli.js uninstall --contract server/contracts/installer-<appId>.contract.example.json --root . --log server/contracts/installer-<appId>.uninstall.log.jsonUninstall supports payload-file deletion actions:
delete-filefor app payload removal during uninstall.
Dry-run mode:
node server/tools/installer-cli.js install --contract server/contracts/installer-<appId>.contract.example.json --root . --dry
node server/tools/installer-cli.js uninstall --contract server/contracts/installer-<appId>.contract.example.json --root . --dryA package is not ready unless all checks pass.
Contract and marker checks:
- Install dry-run returns
ok: trueandrollback: false. - Uninstall dry-run returns
ok: trueandrollback: false. - Installed blocks include
//JsonEntryId: "<entryId>". - Next empty slot remains after each inserted block.
Focused test checks:
node --test tests/unit/installer-marker-engine.test.jsnode --test tests/unit/installer-cli.test.jsnode --test tests/unit/installer-vfs-phase-ab.test.js
Full regression check:
npm.cmd test
Manual UI smoke checks:
- App appears in launcher/nav as expected.
- App window opens and closes correctly.
- App content loads correctly from non-core HTML file.
- Create app HTML payload file.
- Add or confirm safe marker slots in target registration files.
- Create installer contract with install and uninstall actions.
- Run install dry-run.
- Run install apply.
- Run uninstall dry-run.
- Run uninstall apply.
- Reinstall apply.
- Run focused tests.
- Run full test suite.
- Perform manual UI smoke checks.
This workflow verifies forward and reverse paths before cleanup/refactor touches the same files.
Use Hello World as the working reference package:
- Payload:
project/client/apps/non-core/core/tab-hello-world.html - Contract:
project/server/contracts/installer-hello-world.contract.example.json - Install log example:
project/server/contracts/installer-hello-world.reinstall.log.json - Uninstall log example:
project/server/contracts/installer-hello-world.uninstall.log.json
This is the practical next step to reduce manual package authoring and support vibe-coded app creation.
Goal:
- Generate a complete installer-ready app package from a short user prompt.
Phase outline:
- Intake schema
- collect
appId, label, category, icon intent, window size defaults, and feature summary.
- collect
- Payload scaffold generation
- generate
tab-<appId>.htmlwith safe init pattern and minimal UI shell.
- generate
- Contract generation
- generate
installer-<appId>.contract.example.jsonwith install/uninstall actions and stableentryIds.
- generate
- Dry-run validation
- run install/uninstall dry-runs and surface exact errors.
- One-click apply
- run installer apply and optional immediate UI smoke checklist.
Required safeguards:
- Reject invalid
appIdvalues early. - Enforce allowed category keys.
- Enforce installer policy blocks (
markerBoundary,transactionPolicy,loggingPolicy). - Preserve rollback-first behavior for all generated packages.
Suggested MVP outputs:
project/client/apps/non-core/core/tab-<appId>.htmlproject/server/contracts/installer-<appId>.contract.example.jsonproject/server/contracts/installer-<appId>.install.log.json(optional after apply)project/server/contracts/installer-<appId>.uninstall.log.json(optional after apply)