diff --git a/docs/package-contract.md b/docs/package-contract.md index 104136e..5a9e4b9 100644 --- a/docs/package-contract.md +++ b/docs/package-contract.md @@ -73,6 +73,34 @@ Initial permissions: Use the narrowest permission set that fits the package. +## Package settings + +Packages can declare user-configurable settings in the manifest. Firmware stores values outside the package archive in +`/.marginalia/package-state/.json`, so upgrades can replace package files without resetting user choices. + +Supported setting types in manifest v1: + +- `boolean`: toggled on the package settings screen +- `enum`: cycles through a fixed list of string options + +Example: + +```json +{ + "settings": [ + { + "id": "invertScreen", + "label": "Invert screen", + "type": "boolean", + "default": true + } + ] +} +``` + +Setting ids must be stable. If a package removes or renames a setting, firmware may preserve the old value in package +state, but runtime hosts should only read setting ids they understand. + ## Lifecycle entrypoints Package entrypoints are declared by string name in the manifest and mapped by the firmware host. diff --git a/schema/manifest.v1.schema.json b/schema/manifest.v1.schema.json index 64e8f99..cc142db 100644 --- a/schema/manifest.v1.schema.json +++ b/schema/manifest.v1.schema.json @@ -92,6 +92,69 @@ "enum": ["display", "input", "storage", "network", "reader_state", "sleep_state", "settings"] } }, + "settings": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": ["id", "label", "type"], + "properties": { + "id": { + "type": "string", + "maxLength": 48, + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]*$" + }, + "label": { + "type": "string", + "minLength": 1 + }, + "type": { + "type": "string", + "const": "boolean" + }, + "default": { + "type": "boolean" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": ["id", "label", "type", "options"], + "properties": { + "id": { + "type": "string", + "maxLength": 48, + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]*$" + }, + "label": { + "type": "string", + "minLength": 1 + }, + "type": { + "type": "string", + "const": "enum" + }, + "options": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "minItems": 1, + "uniqueItems": true + }, + "default": { + "type": "string", + "minLength": 1 + } + } + } + ] + } + }, "dependencies": { "type": "array", "items": {