Manifest Reference
Every component package contains two files in a warmhub/ directory:
component.json— Component identity (id, name, version)manifest.json— Declarative resource definitions
Both are validated at install time. You can also validate offline with wh component validate <path>.
JSON Schema
Section titled “JSON Schema”Add the $schema field to get IDE autocomplete and inline validation:
{ "$schema": "https://warmhub.dev/schema/component-manifest.v1.json", "component": { ... }, ...}component.json
Section titled “component.json”{ "id": "com.warmhub.MyComponent", "name": "my-component", "version": "1.0.0", "description": "Optional description", "author": "Your Name", "tags": ["research", "ai"]}| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Reverse-DNS identifier (e.g., com.warmhub.MyComponent). Ownership key. |
name | string | Yes | Display name, typically kebab-case. |
version | string | Yes | Semver version string. |
description | string | No | Human-readable description. |
author | string | No | Author or organization. |
tags | string[] | No | Discovery tags. |
The id must match the pattern: one or more lowercase domain segments, followed by one or more PascalCase segments. Examples: com.warmhub.ResearchKnowledge, io.example.MyTool.
manifest.json
Section titled “manifest.json”Top-level structure
Section titled “Top-level structure”All top-level sections except actions are required, but they may be empty arrays or objects. actions is a deprecated legacy field — the CLI still accepts and validates it for older manifests, but install and reconcile ignore it. New components should omit it.
{ "$schema": "https://warmhub.dev/schema/component-manifest.v1.json", "component": { "id": "com.warmhub.MyComponent", "name": "my-component", "version": "1.0.0" }, "shapes": [], "credentials": [], "subscriptions": [], "seeds": [], "health": {}, "teardown": {}}The component section must match the corresponding fields in component.json.
runtimeAccess
Section titled “runtimeAccess”Declare the WarmHub runtime scopes the component’s minted runtime token needs at execution time. This is used only for registered-component setup flows that mint tokens; local installs can still include the field for portability.
"runtimeAccess": { "reads": ["Paper", "ComponentConfig"], "writes": ["Consensus"]}| Field | Type | Required | Description |
|---|---|---|---|
reads | string[] | Yes | Shape names the runtime token may read. |
writes | string[] | Yes | Shape names the runtime token may write. |
Rules:
- Every shape must be declared in
shapes[]or be a known built-in (ComponentInstall,ComponentConfig). - A shape may appear in both
readsandwriteswhen the runtime needs read-before-write behavior, such as revising existing component-owned assertions. - Omitting
runtimeAccessis equivalent to no minted runtime token.
Provisioning modes
Section titled “Provisioning modes”shapes, credentials, and subscriptions support a per-resource provisioning field:
manifest— default. The normal manifest installer creates the resource in the target repo.setup— the registered component’s setup endpoint creates the resource. When minted tokens are enabled, WarmHub includes a setup token the endpoint can use for those writes.
This allows a manifest to mix installer-created and setup-created resources in one package.
shapes
Section titled “shapes”Shapes the component needs in the target repo. Created at install time if they don’t exist.
"shapes": [ { "name": "Paper", "fields": { "title": "string", "url": "string", "score": "number" } }]| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Shape name. |
fields | object | Yes | Field definitions mapping names to WarmHub type descriptors. |
description | string | No | Human-readable description of the shape. |
provisioning | "manifest" | "setup" | No | Which side creates the shape. Defaults to manifest. |
Field types: string, number, boolean, wref (a WarmHub reference string such as Shape/name or Shape/name@v3), arrays, nested objects. See Shapes for details.
credentials
Section titled “credentials”Credential sets the component needs for external API access. With the default provisioning: "manifest", the installer creates the set and the user populates its required keys afterward. With provisioning: "setup", the registered component’s setup endpoint creates and fills the set.
"credentials": [ { "name": "github-creds-<org-name>-<repo-name>", "description": "GitHub API access for fetching repos", "provisioning": "manifest", "requiredKeys": [ { "key": "github_token", "description": "Personal access token with repo scope" } ] }]| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Credential set name. |
description | string | No | What these credentials are for. |
requiredKeys | array | Yes | Keys that must be set. |
provisioning | "manifest" | "setup" | No | Which side creates the credential set. Defaults to manifest. |
requiredKeys[].key | string | Yes | Key name. |
requiredKeys[].description | string | No | What the key is used for. |
Credential names may include the template tokens:
<org-name><repo-name>
These are resolved at install/setup time. For example, veritas-webhook-<org-name>-<repo-name> becomes veritas-webhook-acme-world.
After install, populate keys with:
wh credential set github-creds-acme-world github_token --value ghp_... --repo acme/worldsubscriptions
Section titled “subscriptions”Subscriptions that trigger webhooks on events or schedules.
"subscriptions": [ { "name": "rk/on-paper-add", "trigger": { "kind": "event", "shape": "Paper" }, "kind": "webhook", "webhookUrl": "https://handler.example.com/on-paper", "credentials": ["github-creds-<org-name>-<repo-name>"] }, { "name": "rk/daily-sync", "trigger": { "kind": "cron", "cronspec": "0 6 * * *", "timezone": "America/New_York" }, "kind": "webhook", "webhookUrl": "https://handler.example.com/daily-sync" }]| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Subscription name. Convention: <prefix>/<description>. |
trigger | object | Yes | What fires the subscription. |
kind | "webhook" | "cron" | No | Optional advisory field retained for readability. The CLI derives the effective subscription kind from trigger.kind and ignores this field at install time. |
webhookUrl | string | Yes | Destination URL for deliveries. |
credentials | string[] | No | Credential sets to bind. Currently limited to one. |
fallbackWebhookUrl | string | No | Optional fallback delivery target. |
provisioning | "manifest" | "setup" | No | Which side creates the subscription. Defaults to manifest. |
Event trigger:
| Field | Type | Required | Description |
|---|---|---|---|
kind | "event" | Yes | |
shape | string | Yes | Shape to watch for changes. |
filter | object | No | Additional filter criteria. |
Cron trigger:
| Field | Type | Required | Description |
|---|---|---|---|
kind | "cron" | Yes | |
cronspec | string | Yes | Cron expression (e.g., "0 */6 * * *"). |
timezone | string | No | IANA timezone. Defaults to UTC. |
Initial data created at install time.
"seeds": [ { "kind": "thing", "shape": "ComponentConfig", "name": "my-component", "data": { "version": "1.0.0", "enabled": true } }]| Field | Type | Required | Description |
|---|---|---|---|
kind | "thing" | Yes | Currently only "thing" is supported. |
shape | string | Yes | Shape name. Must be declared in shapes or be a built-in (ComponentConfig). |
name | string | Yes | Thing name within the shape. |
data | object | Yes | Field values. Must conform to the shape’s field definitions. |
ComponentConfig is a built-in shared shape — you can seed things into it without declaring it in shapes.
health
Section titled “health”Configuration reserved for richer wh component doctor diagnostics in a future CLI version.
"health": { "requires": { "shapes": ["Paper", "PaperSummary"], "things": ["ComponentConfig/my-component"], "subscriptions": ["rk/on-paper-add"] }}| Field | Type | Description |
|---|---|---|
requires.shapes | string[] | Reserved for future doctor checks. |
requires.things | string[] | Reserved for future doctor checks. |
requires.subscriptions | string[] | Reserved for future doctor checks. |
All fields are optional. The current CLI accepts this section in the manifest schema, but wh component doctor does not read health.requires.* yet. Today, doctor checks the shapes, subscriptions, credentials, and seeds declared elsewhere in the manifest.
teardown
Section titled “teardown”Behavior when the component is disabled. The current CLI teardown flow reads subscriptions.onDisable; onUninstall is schema-valid but not executed yet.
"teardown": { "subscriptions": { "onDisable": "pause", "onUninstall": "delete" }}| Field | Type | Description |
|---|---|---|
subscriptions.onDisable | "pause" | Action when component is disabled. |
subscriptions.onUninstall | "pause" | "delete" | Reserved for a future uninstall flow. |
Complete example
Section titled “Complete example”{ "$schema": "https://warmhub.dev/schema/component-manifest.v1.json", "component": { "id": "com.warmhub.E2eEcho", "name": "e2e-echo", "version": "1.0.0" }, "shapes": [ { "name": "EchoInput", "fields": { "message": "string", "priority": "number" } }, { "name": "EchoOutput", "fields": { "echo": "string", "processedAt": "string" } } ], "credentials": [ { "name": "echo-api-creds", "description": "API credentials for echo service", "requiredKeys": [{ "key": "api_key", "description": "Echo API key" }] } ], "subscriptions": [ { "name": "echo/process-input", "trigger": { "kind": "event", "shape": "EchoInput" }, "kind": "webhook", "webhookUrl": "https://echo.example.com/process", "credentials": ["echo-api-creds"] } ], "seeds": [ { "kind": "thing", "shape": "EchoInput", "name": "welcome", "data": { "message": "Hello from e2e-echo component", "priority": 1 } } ], "health": {}, "teardown": { "subscriptions": { "onDisable": "pause" } }}Validation
Section titled “Validation”Run offline validation before installing:
wh component validate ./my-componentThis checks:
- JSON syntax and required fields
- Cross-references (subscriptions reference valid credentials, seeds reference valid shapes)
- Duplicate names within sections
- Subscription trigger and webhook validation
- Component ID format (reverse-DNS)
- Consistency between
component.jsonandmanifest.json
Hit a problem or have a question? Get in touch.