Manifest reference
Define identity, UI, Backend, service dependencies, and package contents in curio.json.
Verified September 11, 2026
On this page
A complete UI manifest#
Put curio.json at the project root. The following matches the Web template’s output paths:
{
"schemaVersion": 1,
"id": "dev.example.notes",
"name": "Notes",
"description": "A small desktop notebook.",
"version": "0.1.0",
"engine": { "trove": ">=0.0.1-alpha.1 <0.0.2" },
"ui": {
"entry": "dist/ui/index.html",
"window": { "title": "Notes", "width": 900, "height": 640 }
},
"development": {
"ui": { "url": "http://127.0.0.1:0", "command": ["npm", "run", "dev"] }
},
"build": { "command": ["npm", "run", "build"] },
"package": { "files": ["dist/ui"] }
}
The port-zero configuration requires the dev server to read TROVE_DEV_PORT. Run trove check after editing. The Manifest JSON Schema is available for editor integration; CLI semantic checks are still required.
Identity and compatibility#
| Field | Required | Rules |
|---|---|---|
schemaVersion | Yes | Exactly 1 |
id | Yes | 3–160 characters; lowercase letters, digits, dots, hyphens; alphanumeric first/last character; no host. or trove. prefix |
name | Yes | Display name, 1–100 characters |
version | Yes | Semantic version, such as 0.1.0 |
engine.trove | Yes | Supported Host engine compatibility range |
description | No | Up to 1,000 characters |
icon | No | Relative packaged image path; include the file in package contents |
A manifest must contain ui, backend, or both. Curio version, service version, and schema/protocol version are separate values. Changing the Curio ID changes its identity, including its storage namespace.
UI and window#
ui.entry is required when ui exists. It points to a packaged HTML file, relative to the Curio root. Optional ui.window fields include:
| Field | Accepted value |
|---|---|
title | String, up to 200 characters |
width, height | Integer; width 240–10,000, height 160–10,000 |
minWidth, minHeight | Integer; width 120–10,000, height 80–10,000 |
resizable, transparent, alwaysOnTop | Boolean |
Paths must remain within the package after canonical resolution. Absolute paths, parent-directory escapes, and escaping symlinks are not valid packaged entries.
Backend lifecycle#
This fragment requires a real executable at backend/notes:
{
"backend": {
"entry": "backend/notes",
"args": [],
"transport": "unix",
"lifecycle": "on-demand",
"startWithUi": true,
"startupTimeoutMs": 10000,
"shutdownGraceMs": 2000,
"idleTimeoutMs": 0
}
}
entry, transport, and lifecycle are required. Transport is unix. on-demand starts when needed; closing an installed UI stops a private-only on-demand Backend and its children. A Backend publishing public services remains independent of its window and can serve other Curios. app-start starts with Host and may remain running after the UI closes. startWithUi defaults to false.
Startup timeout defaults to 10,000 ms (100–300,000 allowed). Shutdown grace defaults to 2,000 ms (0–60,000). Idle timeout defaults to 0 (0–86,400,000). args is a string array; optional env contains named string values. Zero idle timeout disables idle reclamation; active calls/subscriptions keep a provider busy. Closing a development window ends that development session. Session credentials are supplied by Host, not hard-coded in this file. See Backend integration.
Services and contracts#
services.provides contains { id, version, contract }. Every provided service requires a Backend and must use the Curio ID as its namespace prefix. contract is a relative JSON file whose service/version must match the declaration.
services.requires contains { id, version, optional? }. Here, version is a supported range and optional defaults to false. An optional dependency does not install or implement the service; your UI must handle its absence. See service examples.
During alpha development, the Host and engine compatibility version are both 0.0.1-alpha.1. Current Curios use >=0.0.1-alpha.1 <0.0.2; Manifest/schema and Wire frame versions continue to evolve independently.
Development and packaging#
| Field | Meaning |
|---|---|
development.ui.url | Loopback HTTP(S) development URL using localhost or 127.0.0.1 |
development.ui.command | Optional argv array to start the UI server |
development.ui.readyTimeoutMs | Default 20,000 ms; range 100–300,000 |
development.backend.mode | managed or external |
development.backend.command | Optional managed-mode argv; defaults to the production Backend entry and args |
build.command | Optional argv array run before staging a package |
package.files | Explicit relative files/directories; not glob patterns |
Commands are arrays, not implicit shell strings. Use ["/bin/sh", "build.sh"] if a build needs shell behavior. Development, build, package, and bindings configuration is removed from the published manifest, without rewriting the source file.
Unknown manifest properties are rejected. Schema validation cannot prove that a compiled entry exists or is executable; pack performs that check on staged production files. See distribution.
Contract and client generation#
The native template configures its private contract and output. This fragment requires an actual contract:export script; obtain the public service contract from its provider.
{
"backend": {
"entry": "dist/backend/curio-backend",
"transport": "unix",
"lifecycle": "on-demand",
"contract": "contracts/backend.json"
},
"bindings": {
"generate": [
"npm",
"run",
"contract:export"
],
"backend": "src/generated/backend.ts",
"services": [
{
"curio": "dev.example.text-tools",
"contract": "contracts/text-tools.json",
"output": "src/generated/text-tools.ts"
}
]
}
}
backend.contract describes this Curio's private Backend; it does not publish a service. bindings.generate is an optional export command argv. bindings.backend is the private client output path. bindings.services maps public service contracts to client files.
trove generate, dev, and pack export and generate. check only validates current contracts and output, reporting bindings.stale when outdated. Paths are relative to the project root and cannot escape it. Bindings are development configuration and are stripped from the published manifest.
backend.contract and bindings.backend are optional private-RPC conveniences. They are unnecessary for public-only Backends or an author-managed internal communication layer. bindings.services[].curio optionally associates a public contract with its owner ID and generates the SDK CurioRegistry declaration; bindings.curios overrides its default path src/generated/curios.d.ts. These fields do not install a provider or declare a version requirement. See service references.