Skip to main content
This page documents MobKit v0.8.34 (mirrored from v0.8.34). MobKit is configured through Rust types passed at startup. This page documents every configuration surface.

MobKitConfig

Top-level configuration for the module runtime.

ModuleConfig

RestartPolicy


DiscoverySpec


PreSpawnData


SDK and Gateway runtime options

The stock SDK gateway (rpc_gateway) consumes the runtime_options object of mobkit/init. The Python and TypeScript builders emit it from their setters; where a row names a setter, that is the only way the SDK reaches the key, and a key with no setter on an SDK can be sent only from a hand-built mobkit/init payload. mobkit_gateway refuses a runtime_options object rather than dropping it. Unsupported nested fields fail initialization with -32602 instead of being silently ignored.

Model fallback

Automatic model fallback is off by default. An enabled policy requires an explicit, non-empty chain; an empty chain never walks the model catalog. Meerkat owns retry eligibility, target admission, credentials, and committed model routing. MobKit forwards that policy without adding its own retry loop. The host file selected by meerkat_config_path accepts [model_fallback]. Rust embedders can pass the same meerkat::Config to UnifiedRuntimeBuilder::meerkat_config. In mob.toml, use [runtime.model_fallback] for a mob default or [profiles.<name>.model_fallback] on an inline profile:
The first present whole table wins: profile, then mob runtime, then host configuration. Omission inherits; an explicit enabled = false wins over an enabled parent. Tables are not merged field by field, so a profile does not silently borrow its parent’s chain. A realm-profile reference cannot carry a sibling fallback override; put it on the referenced profile or the mob runtime. Unknown fallback keys, use_catalog_default_chain, invalid policy values, and enabled = true without a chain are errors. There is no separate runtime_options.model_fallback gateway option. Cross-provider fallback requires explicit cross_provider = true and a usable authorized credential binding; omission does not authorize switching accounts. Targets must pass Meerkat’s context, output-budget, tool and modality admission. Transport failures and empty output are not default fallback triggers. New fallback provenance can cause an unsafe restored route to be held with a typed error. Historical sessions without that provenance are not inferred to be fallback sessions, automatically reverted, or migrated. Existing explicit operator model/provider resume masks retain their authority. The host config setter affects builder-created member session services, not an already-built .mob_spec() service. Native background memory engines currently use their own default config (also fallback-off); this table does not configure those engines. This release does not add fallback overlays, automatic reversion, or a routing-repair CLI.

One-shot mob definition update

Python hosts use the supported builder ceremony on the single activation authorized to change the durable definition:
The builder sends the replacement TOML as top-level mob_config and emits:
The gateway delegates the mutation to Meerkat’s canonical definition CAS. It does not append raw events, rewrite a projection independently, or treat the creation manifest as mutable authority. Remove declare_spec_update(...) from later ordinary restarts. A stale revision or different successor definition raises Python StorageResolutionError; an exact retry returns the already committed successor revision and converges its checked projection. This is a cold-activation ceremony, not a hot reload. Fully shut down the prior runtime before issuing the update: an already-running MobHandle keeps the definition it was constructed with. The CAS and verified-resume fence serialize the update with the next bootstrap, but they do not reconfigure an older live process.
runtime_options.scheduling_files was removed in contract 0.5.0 and is an unsupported field. Move definitions to the durable schedule store through schedule tools or ScheduleService.

Self-hosted models and the Meerkat host config

Meerkat keeps three tables out of the mob definition and in the host config.toml: [self_hosted] (serving endpoints and model aliases), [realm] (backend, auth and binding profiles, including the credential binding every provider = "self_hosted" member resolves through) and [models] (custom model rows). A mob.toml profile refers to them by name only:
mob.toml
config.toml
The alias shape, the realm binding rules and the Gemma 4 worked example are Meerkat’s contract, documented in the Meerkat self-hosting guide; MobKit adds nothing to them. Note that [models.<id>] provider = "self_hosted" is refused by Meerkat’s model registry: self-hosted aliases live under [self_hosted.models] only. [self_hosted] and [realm] belong in the host config, never in mob.toml. MobDefinition::from_toml deserializes without deny_unknown_fields, so a top-level [self_hosted] or [realm] table written into mob.toml used to vanish without a diagnostic and resurface two layers later as a member that could not build. Both binaries now refuse it at init, on the raw TOML text, with one message:
Both binaries answer it as -32602 on the mobkit/init request id (mobkit_gateway when it loads config/mob.toml). [models.<id>] is different from the two tables above. A profile’s model must be catalogued, provider-annotated, or defined under the mob definition’s own [models.<id>] to pass the model check: the check (meerkat_mob::validate_definition, run at init on rpc_gateway and by Meerkat at create time on both binaries) reads only the definition’s tables. So a custom model a profile names by id belongs in mob.toml. A [models] table in the host config still reaches the factory through meerkat_config_path (a provider-annotated profile can use such a row), but it does not satisfy the check, and a profile whose model exists only there and carries no provider is refused at init as UnknownModel.

How the host config reaches each surface

The loader reads exactly the named file and merges it over Config::default() with Config::merge_toml_str, the step Meerkat applies to a discovered .rkat/config.toml: no directory walk and no home-directory fallback, so what the gateway loads is what the operator named. Adoption is never silent: mobkit_gateway logs one INFO line naming the adopted file and whether the init param or the workspace convention produced it. A file that cannot be read or does not parse or does not validate refuses init (rpc_gateway: -32602, runtime_options.meerkat_config_path: failed to read meerkat config <path>: ..., meerkat config <path> is invalid: ... or meerkat config <path> does not validate: ...; mobkit_gateway: -32602 on the request id, init params: meerkat_config_path: ...), because an operator who pointed the gateway at a file expects that file in force. Validation is Meerkat’s own Config::validate against the canonical catalog, the step rkat and rkat-rpc run after every load: a [self_hosted.models.<id>] alias whose server is not declared, a [models.<id>] row colliding with a catalog id, or a zero compaction threshold is refused at init instead of killing the first member build. The gateway’s own declarations stay layered on top: member_comms_address and compaction on rpc_gateway, compaction on mobkit_gateway, and a profile’s own auto_compact_threshold still wins per member.

The init model check

rpc_gateway checks every inline profile’s model before the mob exists, by Meerkat’s own rule (meerkat_mob::validate_definition, narrowed to its UnknownModel diagnostic): a model is acceptable when it is catalogued, or defined under this definition’s [models.<id>], or provider-annotated (provider = "self_hosted" with a self_hosted_server_id, for one). This is the rule rkat mob validate documents and MobBuilder::create applies at bootstrap. A refused model is -32602 with the profile named and, when a catalog id is close, a Did you mean one of: ...? hint (the common cause is a dated id such as claude-sonnet-4-5-20250514 for claude-sonnet-4-5). Only that one diagnostic is adopted at init on purpose: the rest of the set (missing skill refs, wiring, flows) is Meerkat’s to refuse at create time. mobkit_gateway has no pre-check; Meerkat runs the same validation when it creates the mob. Provider-annotated profiles bypass the refusal. By Meerkat’s rule a profile that sets provider = "..." is resolvable whatever its model string says, so a dated or misspelled id on such a profile (every HomeCore profile carries provider = "openai") passes init and surfaces at the first LLM call. rpc_gateway does not add a second refusal authority for that case; it logs one WARN per such profile at init naming the profile, the model and the closest catalog ids (profiles.<p> model '<m>' is provider-annotated ... a typo surfaces at the first LLM call. Did you mean one of: ...?). A provider = "self_hosted" alias is checked against the host config’s [self_hosted.models] instead and warned about only when it is not registered there. Catalogued and [models.<id>]-defined models warn about nothing. Earlier releases compared the model string against the static catalog alone, so a [models.<id>] custom model and every self-hosted alias were refused at init on rpc_gateway while mobkit_gateway accepted them and then failed at the first member build with “self-hosted model ’..’ is not registered in config”; both binaries now agree, and with meerkat_config_path the member builds.

Member role migrations

role_migrations is a top-level mobkit/init param, a sibling of runtime_options rather than a field inside it. On rpc_gateway, runtime_options is a closed allowlist and unknown keys are a hard error, so nesting the declaration there fails initialization with unsupported runtime_options fields: role_migrations. A durable member whose role changed refuses to resume: Meerkat returns MobError::MemberRoleMigrationRequired rather than silently restamping the member’s durable role, comms name and binding together. The host clears that refusal by declaring, for one boot, which exact identity is migrating and which role it is migrating from.
Python hosts declare the same thing through the builder:
.role_migrations([...]) accepts RoleMigrationDeclaration dataclasses or plain dicts and validates both; a conflicting pair raises ValueError; leaving the setter unused emits no role_migrations key at all. The TypeScript builder exposes no equivalent setter. The two gateway binaries, whose names differ by one word, refuse bad payloads differently and install accepted ones under different conditions. Declarations that reach neither identity plane arm nothing, because there is no identity plane to migrate on. See roster and member lifecycle for the operator view of the refusal.

Mob profile tools ([profiles.*.tools])

The mob definition (.mob("config/mob.toml"), or the mob_config string of mobkit/init) is Meerkat’s MobDefinition. Each [profiles.<name>.tools] table is meerkat-mob’s ToolConfig, and every boolean in it defaults to false. The table has no unknown-key check, so a misspelled key (comm = true) is dropped and the flag it meant to set stays false.
The mob-communication skill is preloaded for every member regardless of these flags. Agent-side spawns that inherit the parent’s tool filter open every category, including comms, before the inherited allow-list is applied, so the comms refusal is a host-spawn (mobkit/ensure_member) behaviour; an agent spawn of a comms = false profile silently runs with comms on.

WorkGraph

rpc_gateway constructs a realm-scoped WorkGraphService on every launch unless runtime_options.workgraph is false (the default is true, so a launch that never mentions the key has one). The service backs the member workgraph_* tools, the mob-executor attention overlays and the mobkit/workgraph/* RPCs. mobkit_gateway has no switch: its persistent mode attaches the durable store from the workspace state dir (same degraded posture on open failure) and its default ephemeral launch is memory-backed. The namespace grant is issued by the gateway, not the host. Meerkat refuses to build an agent that has WorkGraph tools and no host-issued WorkGraphNamespaceGrant. Whenever MobKit installs the tools it takes the grant from the service it just built, so the grant names the same scope the tools are pinned to: realm mob.<mob definition id> (Meerkat’s canonical mob realm, the one every other realm-scoped store for the mob uses; if it cannot be formed the raw id is used and Meerkat’s own validation names both realms) and namespace default. Every workgraph_* tool call has its realm_id and namespace arguments overwritten with that scope and all_namespaces removed, so a member cannot wander into another mob’s graph. The meerkat WorkGraph guide’s “embedding hosts must issue the grant in the agent build” is a Rust-embedder instruction; SDK hosts have nothing to issue. The tools stay per-profile: a member sees them only when its profile sets tools.workgraph = true, while the mobkit/workgraph/* RPCs are available whenever the service exists.

Storage layout and durability

MobKitStorageLayout is the single path authority for storage roots and the canonical top-level database locators; no gateway or builder surface derives state-dir file names or resolves ambient roots ($XDG_STATE_HOME, $HOME) on its own, and a CI gate (tests/storage_gate.rs) keeps it that way. Feature code owns relative names beneath the layout’s roots (the blob directory’s internal sharding, per-realm agent-memory files). Canonical spellings (decided once; stores shared with Meerkat keep Meerkat’s names, MobKit-owned files converge on *.sqlite3): Canonical-name-first probing. Opening a slot resolves the canonical name first, then probes the known legacy spellings in the same directory. Exactly one spelling → it is used where it lies (no rename at open). Two spellings of the same store → the gateway refuses to start (error -32014, “file-name twins”) and points at mobkit/storage/doctor; physical renames happen only through the storage migrate verb, under the maintenance fence. Durability classes and the declaration requirement. Every composed slot resolves to a durability class (durable / scratch) and a resolution (persistent / declared_ephemeral / non_persistent). A durable-class slot may run non-persistent only as an explicit declaration (runtime_options.runtime_store, runtime_options.event_log, the Rust builder’s ephemeral_runtime_store(true) / ephemeral_blobs(true)) — never as a silent fallback; undeclared gaps are startup errors that SDKs surface as the typed StorageResolutionError (-32014). The sanctioned boot-without degradations (schedule or workgraph store open failure) disable the feature and appear as degraded slots. Storage census surfaces. The resolved picture rides the storage object on mobkit/status, mobkit/capabilities, and mobkit/storage/doctor: blob_durability / blob_store_persistent (H1), session_store_incremental (H2), and the per-slot slots array (domain, class, resolution, backend, degraded, optional detail).
Changelog policy. Any storage file rename or table move gets the binary-rename treatment: an explicit, loud changelog entry naming the old and new spellings — operators read these files directly.

Identity bootstrap

Calling a Rust or Python identity_bootstrap_mode setter is an explicit identity-first configuration and therefore requires a roster provider for all three modes. Leave the setter unused to retain a classic non-identity gateway; a configured roster with no mode continues to use eager materialization. mobkit/status_identity_bootstrap returns a non-blocking typed snapshot. mobkit/wait_identity_bootstrap accepts target = "materialized" or "startup_ready"; terminal broken identities return with ready = false rather than leaving the barrier pending indefinitely. Provider or restore failures that apply to the whole pass are reported in the snapshot’s optional error field. The stock persistent gateway also advertises a private shutdown handshake and its bounded stdio_shutdown_horizon_ms in the mobkit/init result. SDK hosts keep stdin and provider callbacks open until that handshake completes, then close the process. The current 335-second horizon covers an already-admitted provider callback, runtime event and mob drains, the final lease-release callback, and bounded response-delivery/reaping margin. Provider operations must resolve or reject within their public 120-second contract. The Python host allows 125 seconds for event-loop completion before cancelling that callback; the TypeScript host exposes the same cancellation as an optional ProviderCallbackContext and suppresses late callback responses; the gateway enforces a final 130-second hard wire deadline. Provider rejection, timeout, or cancellation is pre-commit: an implementation must not commit a replacement grant or other external authority after cancellation is observed. Older and custom gateways that do not advertise the handshake retain the EOF shutdown protocol. If the gateway exhausts its runtime deadline, it reports incomplete cleanup; the SDK still reaps the bounded child process and then surfaces the failure. Rust hosts that dispatch JSON-RPC from an Arc<UnifiedRuntime> should call handle_unified_rpc_json_arc (or the corresponding with_live_arc entrypoint). That transfers runtime ownership to supervised identity mutations, so a disconnected request cannot cancel a cross-mob operation between its commit and rollback points. The borrowed dispatcher fails identity-owned cross-mob mutations closed because it cannot provide that ownership guarantee.

mobkit_gateway identity roster

identity_roster is a top-level mobkit/init param of mobkit_gateway (typed InitParams), the standalone counterpart of the SDK roster provider that rpc_gateway reaches through .roster(...) callbacks; rpc_gateway has no identity_roster key. It is an array of DurableAgentSpec objects and seeds the desired identity roster for identity_first: true (the default):
At boot the seed becomes the MutableRosterProvider and restore_flow runs over it: the roster is validated, continuity is resolved for every listed identity, and each non-Broken identity is created or resumed. Omitting the param is an empty seed, so the gateway starts with no identities and mobkit/ensure_member adds them at runtime (it upserts the same provider). The seed is boot-scoped like role_migrations: it is never persisted, and an identity missing from the next boot’s seed is not restored on that boot (its continuity record is untouched). Under identity_first: false the param is parsed and ignored, not refused.

ConsoleUiConfig

View-level configuration for the stock console. mobkit_gateway discovers config/console.toml in the conventional workspace layout; rpc_gateway accepts the same file via runtime_options.console_config_path, and the TypeScript builder exposes .consoleConfig("config/console.toml"). The config is normalized and projected through GET /console/experience as console_config.
Agent grouping selectors and badge fields support labels.<key>, label:<key>, raw label keys, and direct fields such as group, subgroup, role, kind, identity, member_id, and agent_id.
ConsoleUiConfig is intentionally view-level. It controls presentation, ordering, labels, default pins, and links; it does not decide runtime authorization, routing, or whether an agent exists.

AuthPolicy

AuthProvider


ConsolePolicy

For standalone mobkit_gateway launches, pass console_read_only: true in the mobkit/init params or set MOBKIT_CONSOLE_READ_ONLY=true. This setting is part of the gateway resume fingerprint, so toggling it creates or resumes the matching runtime instead of reusing a runtime launched with the opposite policy. mobkit_gateway takes the HTTP exposure knobs as top-level mobkit/init params rather than runtime_options: http_listen (HOST:PORT, default 127.0.0.1:0; also --http-listen or MOBKIT_HTTP_LISTEN_ADDR, the init param winning), allow_remote (also --allow-remote or MOBKIT_HTTP_ALLOW_REMOTE=1) and http_public_base_url. Its console is always open, so a non-loopback http_listen is refused unless allow_remote is set. Every init-param refusal on this binary (http_listen parse, the exposure gate, http_public_base_url, meerkat_config_path, compaction, a [self_hosted] table in mob.toml) answers -32602 on the request id, and a listener bind failure -32603 on the request id. The listen address and the advertised base both join the resume fingerprint like --control-listen, so a relaunch that changes either creates a runtime with the declared values instead of reporting the previous launch’s. The mirror rule holds on rpc_gateway: the same four keys sent top-level there are refused with -32602 naming their runtime_options.* home. See Deployment.

Console auth by surface

require_app_auth defaults to true, and the SDK gateway’s decision state without auth_config trusts no signing key, so the default console is closed to every caller (each request answers 401 missing_credentials or a token failure). Opening it is an explicit, per-surface choice: An open console is a deployment decision. Use it only behind a loopback bind or a reverse proxy that authenticates; for anything shared, configure auth_config (Python .auth(...), TypeScript .auth(...)) instead.

RuntimeOpsPolicy

v0.1 enforces single-replica deployments. Setting replica_count to any value other than 1 produces DecisionPolicyError::ReplicaCountMustBeOne.

LocalJsonMemoryBackendConfig

For SDK builds that boot through rpc_gateway, state_path is derived from .persistent_state(path) as <path>/memory-ledger-state.json; callers provide only backend: "local_json" (and optionally health_check_endpoint). The legacy ElephantMemoryBackendConfig / backend: "elephant" shape is deprecated: it was always local JSON persistence plus a health check — no data ever reached Elephant — and it converts to this config on load. Real Elephant integration is the wire-boundary provider described in docs/design/memory-hub-roadmap.md. Ownership of the assertion ledger. The file is a snapshot of runtime state, not a log that other writers may append to. MobkitRuntimeHandle loads it exactly once at bootstrap and keeps assertions and conflicts in memory as the authority; every mobkit/memory/index (host calls, and the Steward’s conflict signals when agent_memory.steward is enabled) serializes the entire in-memory state and atomically replaces the file, with no re-read, lock or modification check. A direct edit is therefore invisible until the next boot and overwritten by the next flush; single-writer is a convention MobKit does not enforce with a lock. Retention is capped at 4,096 assertions, oldest evicted first, at index time and at load. At load, a structurally malformed file (an entry missing assertion_id, entity, topic, store, fact or indexed_at_ms) refuses the boot with MobkitRuntimeError::MemoryBackend, while a well-formed entry whose entity, topic or store is not canonical, or whose fact is empty, is dropped without a diagnostic. Append through mobkit/memory/index, Python MobHandle.memory_index(...), TypeScript handle.memoryIndex(...), or Rust MobkitRuntimeHandle::memory_index / UnifiedRuntime::memory_index; there is no agent-facing tool, so a host that wants members to write exposes one over the handle. This ledger is distinct from the agent_memory injection and turn-surface ledgers below.

Agent memory injection

agent_memory is separate from mobkit/memory/*. It is hot identity-scoped memory plus prompt injection: during create/resume/materialize and ordinary identity-first turns, MobKit asks an AgentMemoryProvider for memories keyed by AgentIdentity and injects a bounded, quoted observation summary. With the current Meerkat 0.8.32 pairing, ambient per-turn memory requires runtime_mode = "turn_driven"; remove this restriction after the Meerkat 0.8.33 carrier change lands. The bundled gateway provider is one SQLite database per realm under <persistent_state>/agent-memory (store: "sqlite", the only live gateway store). The earlier per-identity markdown files are import-only: store: "markdown" is refused at init with a migration verdict, and pointing SQLite at the same directory imports a realm’s un-imported markdown files when that realm is first accessed and its SQLite connection is opened, preserving ids, tag content and timestamps and renaming each original <file>.imported rather than deleting it (tags are collated on insert, so tag ORDER is not preserved - assert on the set, not the sequence). The path is server-owned and cannot be overridden from SDK init input. Elephant remains an optional deeper knowledge backend for graph/document/truth/provenance use cases and is not required for this hot path. With the SQLite store, build-time injection also composes a metadata index (record ids, kinds, titles, descriptions, human-phrased age) over the identity’s readable scopes, budgeted at ~8 KiB, ahead of the selected record bodies. Every injected record is logged to an injection ledger inside the realm database and counted in per-record usage statistics; explicit mobkit/agent_memory/recall reads are counted separately from ambient injection. Inbound anti-spoofing is on by default (defang_inbound: true): every non-steer identity-first send is scanned for reserved memory-envelope markers (the injection header pattern, <mobkit_memory_observation> tags, [mem-token: prefixes) and matches are visibly neutralized before delivery, so a peer message or echoed web content cannot impersonate remembered context. A warning with a hit count is logged whenever defanging fires. Steer sends bypass injection and defanging entirely. Rust builders can use .persistent_agent_memory_stack(config, engines) with .persistent_state(path) to install the full SQLite stack (store plus taint firewall plus the enabled judgment-plane engines). Callers that need a different authority use .agent_memory(provider, config). The former .persistent_agent_memory(...) markdown constructor is removed; legacy markdown is accepted only by the one-shot SQLite importer. Gateway callers can write records with mobkit/agent_memory/remember, read them with mobkit/agent_memory/recall, and delete individual records with mobkit/agent_memory/forget. TypeScript callers can use handle.rememberAgentMemory(identity, { title, body, tags, realm }), handle.recallAgentMemory(identity, { realm, selection, queryText, queryTerms, maxEntries }), and handle.forgetAgentMemory(identity, memoryId, { realm }); Python callers can use handle.remember_agent_memory(identity, title=..., body=..., tags=..., realm=...), handle.recall_agent_memory(identity, realm=..., selection=..., query_text=..., query_terms=..., max_entries=...), and handle.forget_agent_memory(identity, memory_id, realm=...). Writes and deletes are identity-scoped, require the identity to be registered in the identity runtime, and writes become turn context on the next identity-first send, plus build context on materialization/resume/respawn/reset for that identity. A successful write means the configured hot provider accepted the record; it does not mean optional Elephant extraction/enrichment has completed. Bundled SQLite writes enforce the staged-memory validator’s record limits. The retired markdown parser is used only while importing existing files. When selection = "always", the latest memories for the identity are injected. When selection = "contextual" (the default), build-time injection sends synthesized identity/profile/label query text and deterministic terms; per-turn injection sends the raw current identity-first message plus normalized terms. Common stopwords are ignored by the bundled provider and records below the relevance threshold are not injected. MobKit does not send app context or customizer-added instructions to the memory provider. Semantic/vector retrieval remains a provider concern rather than a MobKit runtime authority. Per-turn injection is governed by per_turn_injection. When omitted, the gateway derives the effective policy from the selected memory backend’s library default: "budgeted" for the bundled SQLite store and "off" for the legacy, import-only markdown kind. Set "off" explicitly to disable ambient push. Selected memories travel as typed injected context immediately before the conversational input, rather than being fused into the user message, and Meerkat excludes that role from semantic-memory indexing. Budgeted injection applies an injection ladder: at most ~4 KiB rendered per record, 20 KiB per assembly, and 60 KiB cumulative per delivered session, with records offered at most once per session (cross-turn dedup). The turn-surface ledger records that preparation-time offer; the transcript’s typed injected-context append records delivery at activation. Build-time injection always applies the per-record and per-assembly caps. Automatic build/turn injection uses recall_timeout_ms (default 500, max 30000) and recall_failure_policy (default "skip", or "fail"). With the default skip policy, provider errors and timeouts omit the memory block and allow delivery to continue. Explicit mobkit/agent_memory/recall requests still return provider errors. Agent memory is identity-scoped and is not automatically cleared by session respawn or identity reset. Apps that require privacy reset semantics can call mobkit/agent_memory/forget for specific records or use an AgentMemoryProvider whose lifecycle policy clears memory alongside the app’s identity lifecycle. forget removes records from future recall and injection; it does not erase text already delivered into an active model context, so reset or respawn the identity after deletion when immediate context revocation matters.

BigQueryNaming


ReleaseMetadata

build_runtime_decision_state parses and validates this document on every build, with or without console auth; nothing reads it at serve time, so the check is release governance, not runtime policy. RuntimeDecisionState::local_console fills the canonical value. A malformed document is a DecisionPolicyError::TomlParse whose message names the release metadata JSON.

Trust manifest (mobkit.toml)

Constants

See also