Skip to Content
ReferenceConfig File

Config File

Every gestaltd deployment reads one or more YAML config files. When you pass multiple --config flags, Gestalt merges them left-to-right before validation and bootstrap. The top-level keys are server (listener, encryption, egress, and host-provider selection), authorization (shared subject access policy), providers (named authentication, secrets, telemetry, audit, UI, indexeddb, authorization, workflow, cache, and s3 entries), workflows (config-managed schedules and triggers), and plugins (executable integrations and optional plugin-backed UI mounts):

server: # listener, encryption, egress, host-provider selectors authorization: policies: {} providers: audit: {} authentication: {} authorization: {} cache: {} indexeddb: {} s3: {} secrets: {} telemetry: {} ui: {} workflow: {} workflows: schedules: {} eventTriggers: {} plugins: {}

Load Semantics

${ENV_VAR} references are expanded before YAML decoding. When a referenced variable is unset, Gestalt checks for a corresponding ENV_VAR_FILE variable and reads that file path instead. If neither is set, config loading fails. Use ${ENV_VAR:-} when an explicit empty default is intentional. Unknown YAML fields are rejected.

When multiple config files are loaded, Gestalt applies these merge rules:

  • maps deep-merge left-to-right
  • later scalar values win
  • later lists replace inherited lists
  • null deletes an inherited key

Relative file paths resolve relative to the config file that introduced them. That includes local source paths, iconFile, and server.artifactsDir. Lockfiles and, by default, artifact directories stay rooted at the leftmost config file. --lockfile overrides only the lockfile path.

Several fields carry defaults when omitted: server.public.port defaults to 8080; the runtime secrets manager defaults to built-in env when providers.secrets is omitted; providers.telemetry.default defaults to built-in stdout; and providers.audit.default defaults to built-in inherit. Structured secret refs are resolved during bootstrap, not during YAML parsing.

authorization configures shared subject access policy at the top level.

Layered example

Base config:

server: encryptionKey: ${GESTALT_ENCRYPTION_KEY} public: port: 8080 plugins: github: source: ./plugins/github/manifest.yaml egress: allowedHosts: - api.github.com - uploads.github.com

Override:

server: management: port: 9090 plugins: github: egress: allowedHosts: - api.github.com iconFile: ./icons/github.svg displayName: null

Run:

gestaltd validate --config ./base.yaml --config ./overrides/local.yaml

The resulting config keeps server.public.port, adds server.management.port, replaces plugins.github.egress.allowedHosts, resolves iconFile relative to ./overrides/local.yaml, and deletes the inherited displayName.

server

server: public: host: 0.0.0.0 port: 8080 management: host: 127.0.0.1 port: 9090 baseUrl: https://gestalt.example.com encryptionKey: secret: provider: default name: gestalt-encryption-key apiTokenTtl: 30d artifactsDir: ./state providers: authorization: indexeddb authentication: oidc indexeddb: main authorization: policies: support_staff: default: deny members: - subjectID: user:viewer-user role: viewer - subjectID: user:admin-user role: admin - subjectID: service_account:triage-bot role: viewer

public.host and public.port control the public listener address. Both default to all-interfaces on port 8080.

management.host and management.port bind a separate listener for operator traffic. When management.port is omitted, /admin and /metrics stay on the public listener, a mode best kept to local development or other trusted-network deployments. For production, prefer configuring server.management so the operator surface leaves the public listener entirely.

management.baseUrl is the browser-facing absolute URL for the management listener. It is only needed when /admin is protected with server.admin.authorizationPolicy on a split public/management deployment. In that mode, unauthenticated management /admin requests round-trip through the public listener’s login flow and return to the built-in management /admin route after callback. management.baseUrl must share a hostname with server.baseUrl so the session cookie can be reused across listeners. If server.baseUrl uses https, management.baseUrl must also use https.

baseUrl derives OAuth callback URLs when explicit redirect URLs are omitted, and gives the management admin UI an absolute link back to the public client UI. When unset, the management admin UI omits the Client UI link rather than sending operators to a broken same-origin /.

encryptionKey is the only required server field. It is the root deployment secret, used for encryption and derived session material.

apiTokenTtl controls the lifetime of newly issued API tokens, defaulting to 30d. It accepts Go duration strings (1h, 720h) and day suffixes (30d). artifactsDir is a writable directory for prepared artifacts produced by init and consumed by serve --locked when no CLI override is supplied; it defaults to the config file’s directory. See Configuration for the full init/serve lifecycle.

admin.authorizationPolicy binds the built-in /admin route to one shared subject access policy from authorization.policies. admin.allowedRoles controls which roles may load the built-in admin UI, defaulting to [admin].

admin.ui optionally pins /admin to one named providers.ui.<name> bundle. The selected bundle must ship admin/index.html inside its prepared asset root. When admin.ui is omitted, Gestalt first auto-discovers admin assets from the root-mounted UI bundle (path: /) when that bundle contains admin/index.html, then falls back to the built-in admin shell.

authorization.policies configures shared subject access policies. Each policy resolves a caller to exactly one role by matching canonical subjectID values such as user:<id> or service_account:<id>, then applies a default fallback (allow or deny) when no member matches. Plugins opt into a policy explicitly through authorizationPolicy.

Dynamic grants are plugin-scoped, not policy-scoped. When a plugin sets authorizationPolicy, operators can manage additional dynamic members for that plugin from the built-in admin UI at /admin/?tab=members or through /admin/api/v1/authorization/.... Static policy members always win over dynamic grants, and Gestalt rejects dynamic writes for subjects that already have static authorization on that plugin. The email write field is a user-only convenience alias; subjectId accepts any canonical non-system subject ID, such as user:<id>, service_account:<id>, or another deployment-defined subject kind.

Non-human callers are modeled as canonical subjects, typically service_account:<id>, and authenticate with Gestalt API tokens whose stored owner is that subject. Grant plugin access with authorization.policies or provider-backed dynamic memberships using the canonical subject ID, and store third-party credentials through the configured external credentials provider under the same subject ID.

Plugins without authorizationPolicy are open to any authenticated subject. Bind a plugin to a policy when non-human access should be explicit.

FieldDefaultDescription
public.host0.0.0.0Bind address for the public listener.
public.port8080Port for the public listener.
management.hostBind address for the management listener.
management.portPort for the management listener. Required when management.host is set.
management.baseUrlBrowser-facing absolute URL for the management listener. Required for protected built-in /admin on split public/management deployments.
baseUrlPublic origin URL used for OAuth callbacks and admin UI links.
encryptionKeyRequired. Root encryption key. Typically a structured secret ref.
apiTokenTtl30dLifetime of newly issued API tokens. Go durations or day suffixes (30d).
artifactsDirconfig directoryDirectory for prepared init artifacts.
providers.audit / providers.authentication / providers.authorization / providers.indexeddb / providers.secrets / providers.telemetryOptional selectors for the named host-provider entries under providers.*. Required for IndexedDB whenever more than one entry exists and recommended for other host-provider maps when more than one entry exists.
providerDev.remoteAttachfalseEnables private remote provider-dev attach routes. Requires providerDev.attachmentState: processLocal.
providerDev.attachmentStateRequired when providerDev.remoteAttach is true. Use processLocal to acknowledge that remote attach v1 stores attachment state in this gestaltd process and therefore requires single-replica operation or sticky routing for provider-dev traffic.
runtime.defaultHostedProviderDefault runtime-provider selector for plugins that opt into execution.mode: hosted. This does not move plugins into hosted runtimes by itself.
admin.authorizationPolicyShared subject access policy applied to the built-in /admin route.
admin.allowedRoles[admin]Roles allowed to load the built-in /admin route when admin.authorizationPolicy is set.
admin.uiOptional named providers.ui bundle whose admin/ assets should back /admin. When omitted, Gestalt auto-discovers admin/ assets from the root UI bundle before using the built-in fallback.
authorization.policiesShared subject access policies resolved by canonical subjectID.

When server.management is configured, Gestalt serves /, /api/v1/*, auth routes, and /mcp on the public listener, while /admin, /admin/api/v1/*, /metrics, /health, and /ready move to the management listener. The management listener is intended to be protected by deployment infrastructure such as private networking, VPN, or an internal-only reverse proxy. Gestalt does not apply its own session or API-token auth to /metrics on the management listener. When server.admin.authorizationPolicy is set, Gestalt does apply browser session auth plus role-based policy checks to /admin and /admin/api/v1/*.

runtime

runtime.providers defines named execution backends for executable plugins. These backends are only used when a plugin opts into execution.mode: hosted. If a plugin omits execution or sets execution.mode: local, it still runs on the same machine as gestaltd.

See Providers > Runtime for the lifecycle and capability model behind these fields.

runtime: providers: local: driver: local modal: source: path: ./vendor/gestalt-providers/runtime/modal/manifest.yaml default: true config: app: gestalt-runtime environment: main

server.runtime.defaultHostedProvider supplies the default runtime name for plugins that set execution.mode: hosted without an explicit execution.runtime.provider. The legacy server.runtime.provider field is no longer accepted.

FieldDescription
providers.<name>.driverOptional built-in runtime selector. The only built-in runtime is local.
providers.<name>.sourceSource or provider-release reference for an installable kind: runtime provider such as Modal.
providers.<name>.defaultMarks the runtime as the default selection when server.runtime.defaultHostedProvider is omitted. Only one runtime may be default.
providers.<name>.configRuntime-provider-specific config blob. Built-ins such as local reject custom config entirely.

runtime.providers.*.config for the Modal runtime provider

The Modal runtime provider creates hosted Linux sandboxes in a Modal app and connects to the plugin over a gRPC tunnel.

runtime: providers: modal: source: path: ./vendor/gestalt-providers/runtime/modal/manifest.yaml config: app: gestalt-runtime environment: main cpu: 2 memoryMiB: 4096 memoryLimitMiB: 6144 timeout: 30m idleTimeout: 10m cloud: aws regions: - us-east-1
FieldDescription
appRequired. Modal app name used to create or reuse sandboxes.
environmentOptional Modal environment name.
cpuOptional CPU allocation for each sandbox. Must be non-negative.
memoryMiBOptional memory request in MiB. Must be non-negative.
memoryLimitMiBOptional memory limit in MiB. Must be non-negative.
timeoutOptional absolute sandbox timeout.
idleTimeoutOptional idle timeout before Modal reclaims the sandbox.
cloudOptional cloud selector passed through to Modal.
regionsOptional region allowlist passed through to Modal.

When a plugin uses the Modal runtime provider, plugins.<name>.execution.runtime.image is required. Modal can still run hosted plugins that need Gestalt-owned services or hostname-based egress when the host is configured for the public relay and proxy path. In practice that means server.baseURL and server.encryptionKey must be set, and the runtime must report a compatible support profile. Without those prerequisites, Gestalt will reject Modal for plugins that need relay-backed host services, egress.allowedHosts, or a server-wide default-deny egress policy.

Hosted runtime images are expected to contain the provider package at the image working directory. Gestalt starts the executable declared by the provider manifest entrypoint and passes the manifest entrypoint args:

plugins: support: source: https://artifacts.example.com/support/v0.1.0/provider-release.yaml execution: mode: hosted runtime: provider: modal image: ghcr.io/example/support-plugin@sha256:...

There is no separate launch source or runtime command override. If runtime.image is set, the image must preserve the provider package layout and make the manifest entrypoint executable from the image working directory.

providers.authentication

Platform authentication is optional. Omit the providers.authentication block entirely to disable it. When platform authentication is enabled, configure one or more named entries under providers.authentication. If more than one entry exists, set server.providers.authentication to pick which one the host should use.

local

The local authentication provider is intended for single-user development on a trusted machine. It uses the same ProviderEntry shape as any other providers.authentication.<name> entry, but it does not require an external identity provider configuration.

oidc

providers: authentication: oidc: source: https://artifacts.example.com/auth/oidc/v0.0.1-alpha.1/provider-release.yaml config: issuerUrl: https://login.example.com clientId: ${OIDC_CLIENT_ID} clientSecret: secret: provider: default name: oidc-client-secret redirectUrl: https://gestalt.example.com/api/v1/auth/login/callback allowedDomains: - example.com scopes: - openid - email - profile sessionTtl: 24h pkce: true displayName: Company SSO allowInsecureHttp: false pkceVerifierTtl: 1h pkceVerifierMaxItems: 10000

Two fields are required: issuerUrl (the OIDC discovery base URL) and clientId. clientSecret may be omitted for PKCE-only public clients.

redirectUrl defaults to a path derived from server.baseUrl. allowedDomains restricts login by email domain. scopes defaults to openid, email, and profile.

sessionTtl controls session token lifetime and defaults to 24h. Set pkce to true to enable Proof Key for Code Exchange. displayName controls the label shown in the login UI, defaulting to SSO.

issuerUrl and all discovered OIDC endpoints must use https:// by default. Set allowInsecureHttp: true only for local loopback development against issuers such as http://127.0.0.1:8080 or http://localhost:8080. Non-loopback http:// endpoints are always rejected.

pkceVerifierTtl and pkceVerifierMaxItems are optional PKCE cache controls. They default to 1h and 10000 in-flight login attempts, and both must be greater than zero when set.

OIDC checks email_verified when the claim is present. Unverified accounts are rejected.

providers.authentication shape

Authentication providers use the same ProviderEntry shape under providers.authentication.<name>. First-party authentication providers are published under github.com/valon-technologies/gestalt-providers/auth/.

FieldDescription
defaultMarks this named authentication entry as the default selection when server.providers.authentication is omitted.
sourceEither a local provider manifest path, a published provider-release.yaml metadata URL, source.url, or source.githubRelease for a GitHub-hosted release asset.
source.authOptional metadata-fetch auth for release sources, including direct metadata URLs and source.githubRelease.
configProvider-specific config passed into the authentication provider.
envExtra environment variables passed to the provider process.
egress.allowedHostsOutbound host allowlist. For executable plugins, this is only a complete boundary when a supported sandboxed runtime is active.

providers.indexeddb

Indexed databases are provider-based. Configure one or more named entries under providers.indexeddb, then set server.providers.indexeddb to the name the host should use for system storage. First-party indexeddb providers are published at github.com/valon-technologies/gestalt-providers/indexeddb/<name>.

server: providers: indexeddb: main providers: indexeddb: main: source: https://artifacts.example.com/indexeddb/relationaldb/v0.0.1-alpha.1/provider-release.yaml config: dsn: ${DATABASE_URL}

The exact config fields depend on the selected external indexeddb provider package. Gestalt itself does not have a built-in indexeddb driver matrix; it loads the configured provider process and passes the selected providers.indexeddb.<name>.config block through to that provider.

Common first-party IndexedDB packages:

ProviderPackage pathConfig fields
RelationalDBgithub.com/valon-technologies/gestalt-providers/indexeddb/relationaldbdsn
DynamoDBgithub.com/valon-technologies/gestalt-providers/indexeddb/dynamodbtable, region, optional endpoint
MongoDBgithub.com/valon-technologies/gestalt-providers/indexeddb/mongodburi, optional database

providers.authorization

Authorization providers are host-scoped policy engines and relationship stores. Configure one or more named entries under providers.authorization, then set server.providers.authorization to the name Gestalt should use for dynamic subject authorization decisions, relationship storage, model lifecycle, and built-in admin authorization APIs. First-party authorization providers are published at github.com/valon-technologies/gestalt-providers/authorization/<name>.

server: providers: indexeddb: main authorization: indexeddb providers: indexeddb: main: source: https://artifacts.example.com/indexeddb/relationaldb/v0.0.1-alpha.1/provider-release.yaml config: dsn: ${DATABASE_URL} authorization: indexeddb: source: https://artifacts.example.com/authorization/indexeddb/v0.0.1-alpha.1/provider-release.yaml config: indexeddb: main

Authorization providers are optional only when you are relying on static human policy members from config. When configured, Gestalt uses the selected provider for dynamic subject plugin/admin authorization, relationship storage, model lifecycle, and the built-in admin authorization APIs under /admin/api/v1/authorization/....

If providers.authorization is omitted, static policy members under authorization.policies still work, but there is no provider-backed relationship store and the dynamic subject authorization control plane is unavailable.

The exact config fields depend on the selected authorization provider package. The first-party authorization/indexeddb provider expects the name of a host IndexedDB provider and stores authorization models plus relationships there.

FieldDescription
defaultMarks this named authorization entry as the default selection when server.providers.authorization is omitted.
sourceEither a local provider manifest path, a published provider-release.yaml metadata URL, or source.githubRelease for a GitHub-hosted release asset.
authOptional inline source auth for remote release sources, including direct metadata URLs and source.githubRelease.
configProvider-specific config passed into the authorization provider.
envExtra environment variables passed to the provider process.
egress.allowedHostsOutbound host allowlist. For executable plugins, this is only a complete boundary when a supported sandboxed runtime is active.

providers.workflow

Workflow providers back global runs, schedules, and triggers. Configure one or more named entries under providers.workflow, then reference them from top-level workflows.schedules.*.provider or workflows.eventTriggers.*.provider. There is no server.providers.workflow: config-managed workflow objects choose a provider explicitly, or inherit the sole/default workflow provider when provider is omitted. User-owned schedules and triggers use the same provider pool through /api/v1/workflow/schedules, /api/v1/workflow/event-triggers, and gestalt workflow ....

providers: indexeddb: workflow_state: source: https://artifacts.example.com/indexeddb/relationaldb/v0.0.1-alpha.1/provider-release.yaml config: dsn: ${DATABASE_URL} workflow: local: source: https://artifacts.example.com/workflow/indexeddb/v0.0.1-alpha.1/provider-release.yaml indexeddb: provider: workflow_state db: workflow objectStores: - schedules - event_triggers - runs config: pollInterval: 1s workflows: schedules: nightly_sync: provider: local cron: "0 3 * * *" timezone: America/New_York target: plugin: name: roadmap operation: sync_items eventTriggers: item_updated: provider: local match: type: roadmap.item.updated target: plugin: name: roadmap operation: sync_items

providers.workflow.<name>.indexeddb is optional. When present, it binds a named host IndexedDB provider into the workflow provider. indexeddb.db defaults to the workflow provider name, and indexeddb.objectStores can allowlist logical stores exposed through that binding.

FieldDescription
defaultMarks this named workflow entry as the default selection when a config-managed workflow object or API request omits provider.
sourceEither a local provider manifest path, a published provider-release.yaml metadata URL, or source.githubRelease for a GitHub-hosted release asset.
authOptional inline source auth for remote release sources, including direct metadata URLs and source.githubRelease.
configProvider-specific config passed into the workflow provider.
indexeddbOptional host IndexedDB binding for the workflow provider, including provider, optional db, and optional objectStores.
envExtra environment variables passed to the provider process.
egress.allowedHostsOutbound host allowlist. For executable plugins, this is only a complete boundary when a supported sandboxed runtime is active.

providers.agent

Agent providers back global agent sessions and turns. Configure one or more named entries under providers.agent. There is no server.providers.agent: each session request either selects a provider explicitly or inherits the sole/default providers.agent entry when provider is omitted. The same provider pool is used by the global agent API/CLI and by plugins that call the host agent manager.

providers: agent: simple: source: ./providers/agent/simple/manifest.yaml default: true indexeddb: provider: default db: simple_agent execution: mode: hosted runtime: provider: modal image: ghcr.io/valon/gestalt-python-runtime:latest pool: minReadyInstances: 1 maxReadyInstances: 4 startupTimeout: 2m healthCheckInterval: 30s restartPolicy: always drainTimeout: 1m config: runStore: runs idempotencyStore: run_idempotency defaultModel: fast aliases: fast: openai/gpt-4.1-mini deep: anthropic/claude-sonnet-4-20250514

Agent providers receive canonical session and turn requests with messages, optional resolved tools, optional responseSchema, and provider-specific config. Agent providers that need durable state can opt into a host IndexedDB binding with indexeddb; the provider process then uses the SDK IndexedDB helper against GESTALT_INDEXEDDB_SOCKET.

Agent providers may also opt into a hosted runtime with execution.mode: hosted, using the same runtime-provider selection model as executable plugins. When providers.agent.<name>.execution.mode is hosted, gestaltd starts the agent provider inside the selected hosted runtime instead of launching it directly on the gestaltd host. Tool callbacks still route back through the host agent socket, and egress.allowedHosts remains the operator-facing egress policy. Legacy providers.agent.<name>.runtime is no longer accepted; use providers.agent.<name>.execution.runtime.

FieldDescription
defaultMarks this named agent entry as the default selection when a session request omits provider.
sourceEither a local provider manifest path, a published provider-release.yaml metadata URL, or source.githubRelease for a GitHub-hosted release asset.
authOptional inline source auth for remote release sources, including direct metadata URLs and source.githubRelease.
indexeddbOptional agent IndexedDB config. indexeddb.provider selects the named providers.indexeddb entry backing the agent’s single IndexedDB SDK socket; unlike plugins, agents do not inherit the selected/default host IndexedDB automatically. indexeddb.db overrides the provider-visible database name and defaults to the agent provider key. indexeddb.objectStores optionally allowlists logical object stores the agent may use.
configProvider-specific config passed into the agent provider.
envExtra environment variables passed to the provider process.
executionOptional hosted execution selection for this agent provider. execution.mode is local or hosted; execution.runtime supports provider, template, image, imagePullAuth, metadata, and pool. imagePullAuth.dockerConfigJson contains Docker config JSON used by runtime providers when pulling private OCI images. pool contains hosted agent lifecycle fields: minReadyInstances, maxReadyInstances, startupTimeout, healthCheckInterval, restartPolicy, and drainTimeout.
egress.allowedHostsOutbound host allowlist. For executable providers, this is only a complete boundary when a supported sandboxed runtime is active.

workflows

Top-level workflows declares config-managed schedules and triggers. These objects are reconciled into the selected workflow provider at startup and invoke an explicit target. A target is exactly one of target.plugin or target.agent.

Config-managed workflows are deployment-owned. They are created from YAML at startup, updated when config changes, and removed when deleted from config. They are distinct from user-owned schedules created through the global workflow HTTP API and CLI. For an end-to-end usage guide, see Workflow.

workflows: schedules: nightly_sync: provider: local cron: "0 3 * * *" timezone: America/New_York target: plugin: name: roadmap operation: sync_items connection: default instance: tenant-a input: mode: incremental paused: false eventTriggers: item_updated: provider: local match: type: roadmap.item.updated source: roadmap target: plugin: name: roadmap operation: sync_items input: reason: sync paused: false

workflows.schedules.*

FieldDescription
providerOptional named providers.workflow entry. When omitted, Gestalt uses the sole/default workflow provider.
target.plugin.nameTarget plugin key from plugins. Required when target.plugin is used.
target.plugin.operationTarget operation ID. Required when target.plugin is used.
target.plugin.connectionOptional target connection name.
target.plugin.instanceOptional target instance name.
target.plugin.inputOptional static input merged into the invocation payload.
target.agentOptional agent target using the same shape as workflow agent requests: provider, model, prompt, messages, tools, responseSchema, metadata, providerOptions, and timeout.
cronRequired. Five-field cron expression.
timezoneIANA timezone name. Defaults to UTC.
pausedWhen true, Gestalt reconciles the schedule in a paused state.

workflows.eventTriggers.*

FieldDescription
providerOptional named providers.workflow entry. When omitted, Gestalt uses the sole/default workflow provider.
target.plugin.nameTarget plugin key from plugins. Required when target.plugin is used.
target.plugin.operationTarget operation ID. Required when target.plugin is used.
target.plugin.connectionOptional target connection name.
target.plugin.instanceOptional target instance name.
target.plugin.inputOptional static input merged into the invocation payload.
target.agentOptional agent target using the same shape as workflow agent requests.
match.typeRequired. Event type matcher.
match.sourceOptional event source matcher.
match.subjectOptional event subject matcher.
pausedWhen true, Gestalt reconciles the trigger in a paused state.

Event trigger matching is exact string matching. match.type is required; match.source and match.subject are optional exact-match filters. Event triggers can be config-managed through YAML or user-owned through the global workflow HTTP API and CLI.

providers.cache

Caches are provider-based and plugin-bound. Configure one or more named entries under providers.cache, then reference those names from plugins.<name>.cache. Unlike IndexedDB, caches are not selected through server.providers.

providers: cache: session: source: https://artifacts.example.com/cache/valkey/v0.0.1-alpha.1/provider-release.yaml config: address: ${VALKEY_ADDR} database: 0 plugins: github: cache: - session

First-party cache providers are published at github.com/valon-technologies/gestalt-providers/cache/<name>.

FieldDescription
sourceEither a local provider manifest path, a published provider-release.yaml metadata URL, or source.githubRelease for a GitHub-hosted release asset.
authOptional inline source auth for remote release sources, including direct metadata URLs and source.githubRelease.
configArbitrary provider-specific config passed through to the cache provider.
envExtra environment variables passed to the provider process.
egress.allowedHostsOutbound host allowlist. For executable plugins, this is only a complete boundary when a supported sandboxed runtime is active.

providers.s3

S3-compatible object stores are provider-based. Configure one or more named entries under providers.s3, then bind them into executable plugins with plugins.<name>.s3. Gestalt does not use S3 providers for its own system state; they are mounted only for plugin code.

providers: s3: assets: source: ./providers/s3/minio/manifest.yaml config: endpoint: http://127.0.0.1:9000 region: us-east-1 accessKeyId: ${MINIO_ROOT_USER} secretAccessKey: secret: provider: default name: minio-root-password plugins: media: source: ./plugins/media/manifest.yaml s3: - assets

The exact config fields depend on the selected S3 provider package. Gestalt’s portable S3 contract covers HeadObject, ReadObject, WriteObject, DeleteObject, ListObjects, CopyObject, and PresignObject, so a single plugin can target AWS S3, MinIO, Cloudflare R2, GCS interoperability mode, or other S3-compatible backends without changing application code.

Plugins can also create host-mediated object access URLs for their scoped S3 bindings with SDK helpers such as TypeScript object.createAccessUrl(...) and Go object.CreateAccessURL(...). These URLs are served by gestaltd at /api/v1/s3/object-access/{token} and require server.baseURL plus server.encryptionKey, because the host signs the logical plugin/binding/object scope before streaming bytes through the configured S3 provider.

providers.secrets

Structured secret refs name the provider explicitly:

encryptionKey: secret: provider: default name: gestalt-encryption-key

Configure one or more named entries under providers.secrets. Every config secret ref uses secret.provider to choose one of those named entries. When providers.secrets is omitted entirely, the runtime secrets manager defaults to built-in env, but structured refs still require an explicit named provider entry. server.providers.secrets continues to select the runtime host secrets provider when one is needed outside config resolution.

providers: secrets: default: source: file config: dir: /etc/gestalt-secrets
SourceConfig fieldsPurpose
envprefixReads secrets from environment variables. Default when providers.secrets is omitted.
filedirReads one secret per file from a base directory. Works with Kubernetes volume-mounted secrets.

Cloud secret backends

Cloud secret managers are external providers configured with a metadata URL source:

providers: secrets: gsm: source: https://artifacts.example.com/secrets/google/v0.0.1-alpha.13/provider-release.yaml config: project: my-gcp-project
ProviderPackage pathConfig fields
Google Secret Managergithub.com/valon-technologies/gestalt-providers/secrets/googleproject (required), version
AWS Secrets Managergithub.com/valon-technologies/gestalt-providers/secrets/awsregion (required), versionStage, endpoint
HashiCorp Vaultgithub.com/valon-technologies/gestalt-providers/secrets/vaultaddress (required), token (required), mountPath, namespace
Azure Key Vaultgithub.com/valon-technologies/gestalt-providers/secrets/azurevaultUrl (required), version

See Secrets Providers for the complete reference and SDK interface.

Bootstrap credentials

Structured secret refs are resolved through the named secret manager at startup, but the secret manager’s own configuration (providers.secrets.<name>.config) cannot use secret refs because it would be self-referential. Use ${ENV_VAR} or ${ENV_VAR_FILE} placeholders for any credentials the secret manager itself needs.

Each provider authenticates to its backing service differently. The env and file providers are built in. The remaining rows apply when using the corresponding external provider from gestalt-providers:

ProviderAuthentication model
envReads from process environment. No external auth needed.
fileReads from local filesystem. No external auth needed.
Google Secret ManagerUses Application Default Credentials . In production, attach a service account or use workload identity. Locally, run gcloud auth application-default login.
AWS Secrets ManagerUses the AWS SDK default credential chain . In production, use an instance profile, ECS task role, or IRSA. Locally, run aws configure or set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
HashiCorp VaultRequires explicit address and token in config. Inject the token via ${VAULT_TOKEN} or ${VAULT_TOKEN_FILE}.
Azure Key VaultUses DefaultAzureCredential. In production, use managed identity. Locally, run az login.

For local development, env or file avoids external dependencies entirely. Switch to a cloud secret manager when deploying to a managed environment where ambient identity is available.

providers.telemetry

Gestalt uses OpenTelemetry  for distributed traces, metrics, and structured logs. Every HTTP request, broker invocation, and plugin gRPC call is automatically traced. See Observability for the emitted metric inventory and Prometheus name translation.

Configure one or more named telemetry entries under providers.telemetry. When the block is omitted, Gestalt synthesizes providers.telemetry.default with built-in stdout. If you configure more than one entry, set server.providers.telemetry to pick the active one.

stdout

providers: telemetry: default: source: stdout config: format: text level: info serviceName: gestaltd

Outputs structured logs to standard output. Traces remain disabled, but metrics are collected locally and exposed through the Prometheus-compatible /metrics endpoint. The built-in admin UI at /admin reads that same scrape surface. This is the default when providers.telemetry is omitted.

FieldDefaultDescription
formattextLog format: text or json.
levelinfoMinimum log level: debug, info, warn, or error.
serviceNamegestaltdAttached to locally exposed metrics.
resourceAttributesExtra key-value pairs attached to local metrics.
metrics.prometheus.enabledtrueToggle the /metrics scrape endpoint.

otlp

providers: telemetry: default: source: otlp config: endpoint: otel-collector:4317 protocol: grpc serviceName: gestaltd insecure: false headers: Authorization: Bearer ${OTEL_TOKEN} resourceAttributes: deployment.environment: production service.version: "1.0.0" traces: samplingRatio: 1.0 metrics: interval: 60s logs: exporter: otlp level: info

Exports to any OpenTelemetry-compatible collector (Jaeger, Grafana Alloy, Datadog Agent) while still keeping local /metrics available by default. The built-in admin UI at /admin reads that same local scrape surface.

FieldDefaultDescription
endpointSDK defaultOTLP collector address.
protocolgrpcTransport protocol: grpc or http.
insecurefalseSkip TLS verification when true.
headersExtra headers on every export request.
serviceNamegestaltdOpenTelemetry service name.
resourceAttributesArbitrary key-value pairs as OTel resource attributes.
traces.samplingRatio1.0Fraction of traces sampled, from 0.0 to 1.0.
metrics.interval60sOTLP metric export interval.
metrics.prometheus.enabledtrueToggle the local /metrics scrape endpoint.
logs.exporterotlpWhere logs go: otlp or stdout.
logs.levelinfoMinimum log level.
logs.formattextLog format when exporter is stdout: text or json.

To keep system logs on stdout while still exporting traces and metrics over OTLP:

providers: telemetry: default: source: otlp config: endpoint: otel-collector:4317 protocol: grpc metrics: interval: 60s logs: exporter: stdout format: json level: info

noop

providers: telemetry: default: source: noop

Disables all telemetry. Instrumentation points remain but produce zero overhead. This disables Prometheus scraping. /metrics returns a clear unavailable response, and the built-in admin UI shows that metrics are unavailable.

Trace spans

LayerSpan nameKey attributes
HTTPgestaltd: {method} {route}Standard HTTP semantic conventions plus resolved gestaltd.* request-surface attributes
Brokerbroker.invokegestalt.provider, gestalt.operation, gestalt.subject_id, gestalt.connection_mode
gRPC plugin and host service trafficPer-RPC spansStandard RPC semantic conventions plus gestaltd.rpc.role, gestaltd.provider.name, and, for host services, gestaltd.host_service.name

providers.audit

Audit records are emitted as structured log entries with log.type=audit. Configure one or more named entries under providers.audit; when the block is omitted, Gestalt synthesizes providers.audit.default with built-in inherit. If you configure more than one entry, set server.providers.audit to pick the active one. See Audit Logging for the event schema and coverage details, and Observability for export options. If you keep providers.audit.default.source: inherit, you can still route audit traffic to a dedicated backend by filtering on log.type=audit in your collector.

inherit

providers: audit: default: source: inherit

This is the default when providers.audit is omitted. Audit records follow the same log route as providers.telemetry: when telemetry uses stdout, audit logs go to standard output; when telemetry uses otlp, audit logs export through the OTLP log pipeline; when telemetry uses noop, audit output is disabled unless you override it here.

providers.audit.<name>.config is not allowed when providers.audit.<name>.source is inherit.

stdout

providers: audit: default: source: stdout config: format: json

Writes audit records to standard output even if the main telemetry pipeline is using a different provider.

FieldDefaultDescription
formattextOutput format: text or json.
levelinfoMinimum audit log level. Setting to warn keeps denied events while suppressing successful ones.

otlp

providers: audit: default: source: otlp config: endpoint: audit-collector:4317 protocol: grpc serviceName: gestaltd insecure: false headers: Authorization: Bearer ${AUDIT_OTLP_TOKEN} resourceAttributes: log.stream: audit

Exports audit records over OTLP without changing where application logs, metrics, or traces go. Use this when you want audit records in a dedicated compliance pipeline while keeping the rest of gestaltd on stdout or a different OTLP collector.

FieldDefaultDescription
endpointSDK defaultOTLP collector address.
protocolgrpcTransport protocol: grpc or http.
insecurefalseSkip TLS verification when true.
serviceNamegestaltdAttached to exported audit logs.
headersExtra headers on every export request.
resourceAttributesExtra key-value pairs attached to audit log exports.

noop

providers: audit: default: source: noop

Disables audit output explicitly. providers.audit.<name>.config is not allowed when providers.audit.<name>.source is noop.

plugins

Each entry in the plugins map is a named plugin backed by an executable provider package. The provider package is the source of truth for operations and transport details. Server config selects the provider, passes provider-specific config, and declares connection policy. The HTTP API route paths still use “integrations” (e.g. /api/v1/integrations) as stable code surface, while the CLI uses the singular plugin command.

plugins: github: displayName: GitHub description: Public GitHub operations iconFile: ./icons/github.svg authorizationPolicy: support_staff ui: path: /github bundle: github_console source: https://artifacts.example.com/plugin/github/v1.2.3/provider-release.yaml surfaces: openapi: baseUrl: https://api.github.com indexeddb: provider: main db: github_plugin objectStores: - tasks - snapshots connections: default: mode: user auth: type: oauth2 allowedOperations: repos.get: alias: get_repo allowedRoles: - admin

Plugin Fields

FieldDescription
displayNameHuman-readable name shown in the UI and API.
descriptionShort description of the plugin.
iconFileSVG icon path, resolved relative to the config directory.
authorizationPolicyOptional shared subject access policy from authorization.policies. When set, host-side operation filtering and execution checks use the resolved role for this plugin, and the built-in admin UI / admin API can manage plugin-scoped dynamic grants for additional members. Static policy members still take precedence.
uiOptional plugin-backed mounted UI binding. Use ui.path plus optional ui.bundle. ui.bundle names a providers.ui entry; omit it to mount the plugin manifest’s owned spec.ui.
sourceRequired. The backing provider source. See source shape below.
source.authOptional metadata-fetch auth for release sources. Use this for source.url, source.githubRelease, or local provider-release.yaml metadata.
authOptional plugin route auth reference. Use auth.provider to reference either the reserved server alias or a named entry from providers.authentication. Gestalt enforces this on plugin HTTP operation routes (/api/v1/integrations/{name}/operations and /api/v1/{integration}/{operation}) and on plugin-backed mounted UIs, including browser-login flows whose next path resolves into that plugin’s mount. Standalone providers.ui bundles, the built-in admin UI/admin API, and /mcp still use the server-wide auth provider in this phase.
configProvider-specific configuration passed into the provider package.
securitySchemesOptional hosted HTTP security scheme overrides merged over the plugin manifest’s spec.securitySchemes. Use this for deployment-specific secrets or for deployment-local hosted HTTP bindings.
httpOptional hosted HTTP binding overrides merged over the plugin manifest’s spec.http. Use this only when a deployment intentionally changes the route path, request body, security scheme, target operation, or acknowledgment response.
surfacesTyped host-side overrides for manifest-declared surfaces, such as surfaces.openapi.baseUrl or surfaces.graphql.url.
connectionsNamed connection declarations. See connections below.
allowedOperationsAllowlist with optional alias, description, and allowedRoles overrides per operation.
providerDev.attach.allowedRolesRoles from this plugin’s authorizationPolicy that may create private remote provider-dev attachments for this plugin. This is denied when omitted, empty, or when the plugin has no authorizationPolicy.
executionOptional executable-plugin execution config. execution.mode is local or hosted; execution.runtime carries the hosted runtime fields.
egress.allowedHostsOutbound host allowlist. For executable plugins, this is only a complete boundary when a supported sandboxed runtime is active.
indexeddbOptional plugin IndexedDB config. indexeddb.provider selects which named providers.indexeddb entry backs the plugin’s single IndexedDB SDK socket; when omitted, the plugin inherits the selected/default host IndexedDB. indexeddb.db overrides the plugin-visible database name and defaults to the plugin key. Schema-capable backends derive plugin scoping from that db name. indexeddb.objectStores optionally allowlists the logical object stores the plugin may use. Plugins then call new IndexedDB() (or the equivalent SDK helper) against GESTALT_INDEXEDDB_SOCKET; they do not choose arbitrary schemas or DSNs at runtime.
s3Optional list of named providers.s3 bindings exposed to the executable plugin through the SDK transport. A single binding also populates the default S3 SDK env var for compatibility.

S3 bindings are exposed as GESTALT_S3_SOCKET_<NAME>. When exactly one S3 binding is configured, Gestalt also sets GESTALT_S3_SOCKET.

plugins.*.source

Every plugin uses a source block to declare its backing provider.

source: https://artifacts.example.com/plugin/github/v1.2.3/provider-release.yaml

Canonical metadata-source auth lives under source.auth. For direct metadata URLs:

source: url: https://artifacts.example.com/plugin/github/v1.2.3/provider-release.yaml auth: token: ${PLUGIN_RELEASE_TOKEN}

Plugin route auth overrides are declared separately:

apiVersion: gestaltd.config/v4 plugins: slack_bot: source: ./dist/provider-release.yaml auth: provider: server

This field changes runtime authentication for plugin HTTP operation routes and plugin-backed mounted UIs. Browser login uses the plugin’s route-auth provider when its next path resolves into that plugin’s mounted UI. Standalone providers.ui bundles, the built-in admin UI/admin API, integration OAuth helper routes, and /mcp still use the server-wide auth provider in this phase. For published providers, source can point at a provider-release.yaml metadata URL directly, or it can describe a GitHub release logically:

source: githubRelease: repo: valon-technologies/toolshed tag: plugins/github/v1.2.3 asset: provider-release.yaml

For local development, source can point directly at a provider manifest path instead.

For local development with a source provider package:

source: ./manifest.yaml

When a remote gestaltd instance is running the provider-dev endpoints, authenticated developers can attach a local implementation for configured plugins that are registered on the remote server and that they are authorized to access with gestaltd provider dev --remote. A path-only attach matches the local manifest source to the remote configured plugin and preserves the remote plugin config; layered --config files are only needed for explicit local config overrides or multi-plugin attach sessions.

Remote provider attach is disabled by default on servers. Enable it explicitly on shared remotes:

server: providerDev: remoteAttach: true attachmentState: processLocal authorization: policies: provider_devs: default: deny members: - subjectID: user:usr_123 role: developer plugins: slack: authorizationPolicy: provider_devs providerDev: attach: allowedRoles: - developer

The attach transport is private to the authenticated owner. The create response includes an attachId for addressing and a one-time dispatcher secret used only by the local CLI for poll/complete traffic. Owner diagnostic list/get routes return redacted attachment metadata and never return dispatcher secrets, runtime environment, host-service env, plugin config, access tokens, or browser binding URLs.

Remote attach v1 stores attachments in the gestaltd process that accepted the create request. attachmentState: processLocal is required as an explicit operator acknowledgement of that model. For load-balanced deployments, treat single-replica operation or sticky routing for attach creation, poll/complete traffic, provider invocations, and provider-owned UI requests as a hard prerequisite before enabling remoteAttach.

Interactive attach creation uses a short-lived browser approval page plus a verification code shown in the initiating terminal. The approving browser session must satisfy the plugin runtime grant. For non-interactive/API-token attach, the caller must satisfy both the plugin runtime grant and a token action grant. The runtime grant comes from plugins.<name>.providerDev.attach.allowedRoles on a plugin with an authorizationPolicy, or from a runtime authorizer that explicitly grants the same action. API tokens must carry permissions[].actions: ["provider_dev.attach"] for every attached plugin; normal provider scopes and operation permissions do not grant attach, and the attach action does not grant operation invocation.

Gestalt synthesizes Go and Rust executable wrappers automatically when needed and runs Python source providers from the module declared in [tool.gestalt].provider.

A local Go source plugin typically looks like:

my-plugin/ go.mod manifest.yaml provider.go
FieldDescription
sourceA local provider manifest path, a published provider-release.yaml metadata URL, source.url, or source.githubRelease for a GitHub-hosted release asset.
source.authOptional metadata-fetch auth for release sources, including direct metadata URLs, source.githubRelease, and local provider-release.yaml metadata.
authOptional plugin route auth reference. Use auth.provider to reference either server or a named providers.authentication entry. Gestalt enforces this on plugin HTTP operation routes and on plugin-backed mounted UIs. Standalone providers.ui bundles, the built-in admin UI/admin API, and /mcp still use the server-wide auth provider in this phase.
envExtra environment variables passed to the provider process.
egress.allowedHostsOutbound host allowlist. For executable plugins, this is only a complete boundary when a supported sandboxed runtime is active.

connections

Connections declare how users authenticate to the upstream service. Only connections.default may define params and discovery. A provider manifest can also declare connections; when both the manifest and config define the same connection name, config values are merged on top of the manifest defaults. See Provider Manifests for the manifest-side schema.

connections: default: mode: user auth: type: oauth2 authorizationUrl: https://accounts.example.com/oauth/authorize tokenUrl: https://accounts.example.com/oauth/token clientId: ${CLIENT_ID} clientSecret: ${CLIENT_SECRET} params: tenant: required: true description: Tenant identifier mcp: mode: user auth: type: mcp_oauth

Connection mode determines how credentials are managed: none requires no credentials, and user stores credentials for the caller’s effective subject. For humans that is typically user:<id>; for non-human API token callers it can be service_account:<id> or another canonical non-system subject ID. Runtime surfaces can also supply system subjects such as system:http_binding:<plugin>:<binding> as the effective credential owner. All connections in a single plugin must share the same mode.

Authentication Shapes

Every connection auth block uses the same shape. type selects the auth strategy: oauth2, manual, bearer, none, or mcp_oauth.

FieldDefaultDescription
typeAuthentication strategy: oauth2, manual, bearer, none, or mcp_oauth.
authorizationUrlOAuth2 authorization endpoint.
tokenUrlOAuth2 token endpoint.
clientIdOAuth2 client identifier.
clientSecretOAuth2 client secret.
redirectUrlderived from server.baseUrlOAuth2 callback URL.
clientAuthbodyHow credentials are sent to the token endpoint: body or header.
tokenExchangeformToken request encoding: form or json.
scopesOAuth2 scopes to request.
scopeParamscopeQuery parameter name for scopes. Set to user_scope for Slack and other providers that use a non-standard parameter.
scopeSeparatorspaceSeparator between scope values.
pkcefalseEnable Proof Key for Code Exchange.
authorizationParamsExtra parameters for the authorization request.
tokenParamsExtra parameters for the token request.
refreshParamsExtra parameters for the refresh request.
acceptHeaderAccept header for the token endpoint.
accessTokenPathJSON path to the access token in the token response.
tokenMetadataFields to extract from the token response and store as connection metadata.

mcp_oauth is an advanced mode for MCP-driven OAuth discovery. It delegates authorization URL and token URL resolution to the upstream MCP server.

Manual auth with custom credential fields

For manual-auth connections, credentials customizes the credential input form. Each entry defines a field the user must fill in, with an optional label, description, and help URL.

Single credential with a custom label:

connections: default: auth: type: manual credentials: - name: token label: API Access Token

Multiple credentials require authMapping to map each field to an HTTP header:

connections: default: auth: type: manual credentials: - name: api_key label: API Key - name: app_key label: Application Key authMapping: headers: DD-API-KEY: valueFrom: credentialFieldRef: name: api_key DD-APPLICATION-KEY: valueFrom: credentialFieldRef: name: app_key
FieldDescription
credentials[].nameUnique, lowercase-with-underscores identifier. Required when auth.type is manual.
credentials[].labelUI display label. Falls back to name when omitted.
credentials[].descriptionHint text below the label. Supports inline links via [text](url).
authMapping.headers.<HEADER>.valueSupplies a static deployer-managed value for a header.
authMapping.headers.<HEADER>.valueFrom.credentialFieldRef.nameReads a header value from the named manual credential field.
authMapping.basic.username / authMapping.basic.passwordBuild the Basic authentication username/password from either a static value or valueFrom.credentialFieldRef.name.

For Basic authentication providers that should collect only an API key while keeping the organization ID static, declare just the user-facing field and map the rest explicitly:

connections: default: auth: type: manual credentials: - name: api_key label: API Key authMapping: basic: username: value: ${MODERN_TREASURY_ORG_ID} password: valueFrom: credentialFieldRef: name: api_key

Post-connect discovery

Post-connect discovery lets a connection fetch a list of resources after the user authenticates, populating a connection parameter from the user’s selection.

connections: default: mode: user auth: type: oauth2 authorizationUrl: https://accounts.example.com/oauth/authorize tokenUrl: https://accounts.example.com/oauth/token params: workspace_id: required: true description: Workspace chosen after connect from: discovery discovery: url: https://api.example.com/workspaces idPath: id namePath: name metadata: workspace_id: id
FieldDescription
discovery.urlURL to fetch the list of resources after connect.
discovery.idPathJSON path to the resource identifier.
discovery.namePathJSON path to the resource display name.
discovery.metadataMaps connection metadata keys to JSON paths in the discovery response.

server.egress

server.egress sets the server-wide default for outbound network access. Per-provider egress.allowedHosts lists declare which hosts each provider may reach. For executable plugins, that declaration is only a complete enforcement boundary when the deployment is using a supported sandboxed runtime.

server: egress: defaultAction: deny plugins: github: egress: allowedHosts: - api.github.com - "*.github.com" my-plugin: source: ./plugins/my-plugin/manifest.yaml egress: allowedHosts: - external-api.com
FieldDescription
defaultActionallow (default) or deny. Applies when a provider has no egress.allowedHosts.

When egress.allowedHosts is set on a provider, Gestalt applies that allowlist to host-mediated outbound checks using exact matches and *.suffix wildcards. When egress.allowedHosts is empty, defaultAction decides: allow permits outbound requests, deny blocks them. Provider-level allowedHosts is no longer accepted; use egress.allowedHosts. For executable plugins, those rules are only a complete security boundary when the plugin is running inside a supported sandboxed runtime rather than relying on host-specific OS wrappers alone.

providers.ui

providers: ui: console: source: https://artifacts.example.com/ui/console/v1.0.0/provider-release.yaml path: /console config: brandName: Acme

providers.ui is a map of ui bundles. Entries may mount directly by setting path, or they may act as named UI bundles that plugins.<name>.ui.bundle binds to plugins.<name>.ui.path. When a plugin manifest declares spec.ui, plugins.<name>.ui.bundle may be omitted entirely and Gestalt synthesizes the mounted UI entry from the plugin-owned reference. /admin remains available regardless. A selected server.admin.ui bundle, or the root-mounted UI bundle when it contains admin/index.html, may also supply the static admin shell while Gestalt keeps the existing /admin auth and API semantics. Omit providers.ui entirely to run headless with no public UI bundles.

Plugin-backed mounted UIs inherit the owning plugin’s dynamic authorization grants when that plugin sets authorizationPolicy. Direct providers.ui.<name>.authorizationPolicy bindings remain static-only.

When authorizationPolicy is set on a mounted UI, the referenced UI manifest must declare spec.routes with non-empty allowedRoles, and at least one route must cover /.

FieldDescription
pathDirect mount prefix for this UI when not bound through plugins.<name>.ui.path.
authorizationPolicyDirect policy binding for this UI when not bound through plugins.<name>.ui.path.
sourceA local UI manifest path, a published provider-release.yaml metadata URL, or source.githubRelease for a GitHub-hosted release asset.
authOptional inline source auth for remote release sources, including direct metadata URLs and source.githubRelease.
configOptional UI-provider config validated against the bundle schema when present.

Validation rules

Structural validation runs at config load time (init, validate, serve). Runtime validation runs only at serve time.

Structural

Each plugin must set source to exactly one loading mode: a local manifest path or a published provider-release.yaml metadata URL.

Host-provider entries use the same ProviderEntry shape. When providers.authentication.<name>, providers.cache.<name>, providers.indexeddb.<name>, or providers.s3.<name> is set, source must be present. providers.authentication.<name>.config, providers.cache.<name>.config, providers.indexeddb.<name>.config, and providers.s3.<name>.config are only allowed when their corresponding source is set.

Only connections.default may define params or discovery. All connections in a plugin must share the same mode.

Each providers.ui.<name> entry must set source to exactly one loading mode: a local UI manifest path or a published provider-release.yaml metadata URL. providers.ui.<name>.config is only allowed when providers.ui.<name>.source is set.

Each plugins.<name> entry may set ui.path to publish a plugin-backed UI. When ui.bundle is set, it must reference an existing UI bundle. When ui.bundle is omitted, the plugin manifest must declare spec.ui. A given UI may be bound by at most one plugin entry. ui.path must use the same path rules as a directly mounted UI.

When server.admin.ui is set, it must reference an existing providers.ui.<name> entry. Runtime startup then requires that entry’s prepared asset root to include admin/index.html.

Each name in plugins.<name>.s3 must reference an existing enabled providers.s3.<name> entry.

Mounted UI bundles are served on the public listener only. The built-in admin UI remains at /admin.

server.egress.defaultAction must be allow or deny.

authorization.policies.<name>.default must be allow or deny when set. Each policy member must set a non-empty subjectID and a non-empty role.

Server listener ports must be greater than zero. When server.management is configured, it must differ from server.public.

Runtime

server.providers.indexeddb, providers.indexeddb, and server.encryptionKey are required at serve time. providers.authentication is optional.