What is changing
ZeroClaw is adding typed, schema-validated plugin config (host PR zeroclaw-labs/zeroclaw#9126). Once it lands, a manifest that requests config_read without declaring config_schema is no longer discovered or installed. The two are a biconditional: declaring a schema without requesting the permission is equally invalid.
This ships without a compatibility shim or grace period. Plugins are a pre-1.0 experimental surface, and an untyped fallback would have to hand a guest values the host cannot type, name, or bound, which is the hole the feature closes. Packages that do not migrate stop being discovered; nothing is silently downgraded.
Every package in this repository requests config_read and none declares config_schema today, so all 31 need migration.
Why the host needs the schema
Operator values are stored as a secret-marked string map, encrypted at rest, and the guest is untrusted code. Before starting a guest the host must know which keys the package may receive and what type each value is. The WIT worlds are fixed and shared across all plugins, so per-package config types cannot live in the ABI. The manifest is the only place the contract can be declared, and additionalProperties = false plus an explicit properties map is what makes the config_read grant enumerable.
What each package needs
Full recipe with examples, limits, and error messages: Migrating to typed plugin config.
Short version, per package:
- Add a closed Draft 2020-12
[config_schema] to manifest.toml covering exactly the keys the plugin reads. Root must be type = "object" with additionalProperties = false; every top-level property needs one explicit type from string, boolean, integer, number, array, object.
- Mark credentials
required so a withheld grant fails closed instead of starting half-configured. Optional keys receive {} when the grant is withheld, so give them guest-side defaults.
- Update the guest to deserialize the injected typed JSON once instead of parsing strings. Booleans, numbers, arrays, and objects arrive as real JSON values.
- Rebuild the component.
- Re-sign, if the package is signed:
config_schema is covered by the manifest signature.
permissions = ["config_read"]
[config_schema]
"$schema" = "https://json-schema.org/draft/2020-12/schema"
type = "object"
required = ["bot_token"]
additionalProperties = false
[config_schema.properties.bot_token]
type = "string"
minLength = 1
[config_schema.properties.poll_interval_secs]
type = "integer"
minimum = 1
Schema limits enforced by the host: 64 KiB serialized, at most 32 levels of nesting, no $id, and $ref must be a local JSON Pointer. Remote references are rejected, so a schema never triggers a network fetch.
Operator-facing change in the same release
[[plugins.entries]] is now keyed by a full-instance key derived from package, capability, and binding (zpi1_...) rather than the package or binding name. Legacy entries are not consulted. zeroclaw plugin info <package> prints the key; fresh installs seed and print it automatically. Worth a line in each package's README where it documents configuration.
Checklist
What is changing
ZeroClaw is adding typed, schema-validated plugin config (host PR zeroclaw-labs/zeroclaw#9126). Once it lands, a manifest that requests
config_readwithout declaringconfig_schemais no longer discovered or installed. The two are a biconditional: declaring a schema without requesting the permission is equally invalid.This ships without a compatibility shim or grace period. Plugins are a pre-1.0 experimental surface, and an untyped fallback would have to hand a guest values the host cannot type, name, or bound, which is the hole the feature closes. Packages that do not migrate stop being discovered; nothing is silently downgraded.
Every package in this repository requests
config_readand none declaresconfig_schematoday, so all 31 need migration.Why the host needs the schema
Operator values are stored as a secret-marked string map, encrypted at rest, and the guest is untrusted code. Before starting a guest the host must know which keys the package may receive and what type each value is. The WIT worlds are fixed and shared across all plugins, so per-package config types cannot live in the ABI. The manifest is the only place the contract can be declared, and
additionalProperties = falseplus an explicitpropertiesmap is what makes theconfig_readgrant enumerable.What each package needs
Full recipe with examples, limits, and error messages: Migrating to typed plugin config.
Short version, per package:
[config_schema]tomanifest.tomlcovering exactly the keys the plugin reads. Root must betype = "object"withadditionalProperties = false; every top-level property needs one explicit type fromstring,boolean,integer,number,array,object.requiredso a withheld grant fails closed instead of starting half-configured. Optional keys receive{}when the grant is withheld, so give them guest-side defaults.config_schemais covered by the manifest signature.Schema limits enforced by the host: 64 KiB serialized, at most 32 levels of nesting, no
$id, and$refmust be a local JSON Pointer. Remote references are rejected, so a schema never triggers a network fetch.Operator-facing change in the same release
[[plugins.entries]]is now keyed by a full-instance key derived from package, capability, and binding (zpi1_...) rather than the package or binding name. Legacy entries are not consulted.zeroclaw plugin info <package>prints the key; fresh installs seed and print it automatically. Worth a line in each package's README where it documents configuration.Checklist