Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration validation

smista.ai validates your configuration and reports every finding as either an error or a warning. Errors make the configuration invalid and must be fixed before smista can use it. Warnings are advisory — they surface potential problems but do not block execution.

When smista validates your configuration it collects all findings in a single pass and reports them together, so you can fix everything at once.

Check each file with the CLI:

smista config check project
smista config check global
smista config check router

CLI / policy configuration (config.toml)

These checks apply to the merged CLI and routing-policy configuration loaded from your global and project configuration, plus any runtime override. CLI configuration validation emits errors only.

CheckSeverityHow to fix
Unknown provider — a routing rule, fallback, or default route references a provider identifier that is not enabled in [providers]ErrorEnable that provider with a [providers.<id>] table, or correct the reference
Invalid glob — a pattern in privacy.restricted_paths, privacy.remote.blocked_paths, or a rule’s paths list fails to compileErrorFix the glob syntax (e.g. close unclosed brackets)
Duplicate rule name — two [[routing.rules]] entries share the same nameErrorGive each rule a unique name
Missing default route — no [routing.default] table is presentErrorAdd [routing.default] with a model field
Invalid fallback — a rule lists its own model as a fallback, or lists the same fallback model more than onceErrorRemove the self-reference or duplicate from fallbacks
Ambiguous rules — two overlapping rules share the same priority value and the same specificity score, making their relative order undefinedErrorGive them distinct priority values or make their match conditions mutually exclusive
Unsafe override — a runtime override sets privacy.remote.mode to a value less strict than the merged config-layer floorErrorDo not weaken the configured privacy mode in a runtime override
Permission widening — a runtime override sets a tool permission (file_read, file_write, shell, etc.) to a less strict value than the config floorErrorKeep the configured stricter permission; runtime overrides may only tighten, never loosen
Inline secret — a provider api_key is a literal string instead of a ${secret:NAME} referenceErrorRemove the value and use smista credentials set, or replace it with a ${secret:NAME} environment-variable reference

Specificity

Two overlapping rules are considered ambiguous when they share both a priority value and the same number of constrained match dimensions (intent, path list, local_only). Rules with mutually exclusive match conditions, such as different explicit intents, are not ambiguous. Give one overlapping rule a lower priority number to resolve the ambiguity:

[[routing.rules]]
name = "review with claude"
priority = 10 # wins over the rule below
intent = "review"
model = "anthropic/claude-sonnet"

[[routing.rules]]
name = "review with gpt"
priority = 20 # distinct priority — no ambiguity
intent = "review"
model = "openai/gpt-5.5-mini"

Unsafe overrides and permission widening

The merged global and project config layers set the safety floor. A runtime override may add restrictions — for example switching a tool from ask to deny — but may not weaken a configured restriction.

# project .smista/config.toml
[privacy.remote]
mode = "deny" # no remote sends

[tools.permissions]
shell = "ask" # shell requires approval
# runtime override — these are rejected
[privacy.remote]
mode = "allow" # error: unsafe override

[tools.permissions]
shell = "allow" # error: permission widening

Model selection (checked at run time)

Two things the CLI does not check during configuration validation are verified later, when the router selects a model for a task — against the facts each provider exposes about its models, not against any config:

  • Model existence — whether the model a rule selects, or any entry in its fallbacks, is actually offered by the provider.
  • Capability requirements — whether a model satisfies a rule’s requires_capabilities. This catches, for example, a rule that needs tool calls but falls back to a local model that cannot call tools.
[[routing.rules]]
name = "tool-using edits"
requires_capabilities = { tools = true }
model = "anthropic/claude-sonnet"
fallbacks = ["ollama/qwen2.5-coder:7b"]

If ollama/qwen2.5-coder:7b does not support tools, the router skips it when this rule needs tool calls and falls through to the next viable option, rather than failing configuration validation up front. Because model facts come from the provider at run time, they are never declared in config.toml.

Router configuration (router.toml)

These checks apply to the smista-router runtime configuration. All must hold for a valid router configuration.

CheckSeverityHow to fix
Invalid portrouter.port is 0ErrorSet a port in the range 1–65535
Invalid hostrouter.host is empty, contains whitespace, includes a port, or is not a valid hostname or IP addressErrorSet a bare hostname or IP address (e.g. 127.0.0.1)
Public bind in embedded moderouter.host is 0.0.0.0 or :: while router.storage.mode = "embedded"WarningBind to 127.0.0.1 unless you intentionally want to expose the local router to the network
Missing storage pathrouter.storage.mode = "embedded" but router.storage.path is not setErrorSet router.storage.path to a writable directory (e.g. .smista/db)
Missing storage URLrouter.storage.mode = "remote" but router.storage.url is not setErrorSet router.storage.url to the SurrealDB WebSocket address (e.g. ws://db:8000)
Local bootstrap in remote moderouter.auth.local_bootstrap_enabled = true while router.storage.mode = "remote"ErrorSet local_bootstrap_enabled = false, or switch to embedded mode
Zero timeout — any of router.limits.request_timeout_ms, router.limits.provider_timeout_ms, or router.limits.tool_timeout_ms is 0ErrorSet a positive value in milliseconds
Zero size limitrouter.limits.max_request_body_bytes or router.limits.max_context_bytes is 0ErrorSet a positive byte limit
Invalid rate limit — rate limiting is enabled but period_ms or burst_size is 0ErrorSet both values above zero, or disable rate limiting
Excessive timeout — a timeout exceeds 3,600,000 ms (1 hour)WarningCheck that the value is in milliseconds, not seconds; lower it if so
Unsafe CORS — CORS is enabled (router.cors.enabled = true) but router.cors.allowed_origins is empty or contains *ErrorList explicit origins: allowed_origins = ["https://app.example.com"]
Invalid OpenTelemetry — export is enabled with an empty endpoint, empty service name, or sample ratio outside 0.01.0ErrorSet a collector endpoint, service name, and valid sample ratio
Ignored provider URLbase_url is set for built-in OpenAI, Anthropic, or GeminiWarningRemove it, or configure a named openai-compat:<name> provider for a custom endpoint

Example: correcting a zero timeout

[router.limits]
# Error: request_timeout_ms = 0
# Fix:
request_timeout_ms = 120000 # 2 minutes
provider_timeout_ms = 180000 # 3 minutes
tool_timeout_ms = 60000 # 1 minute

Example: correcting unsafe CORS

[router.cors]
enabled = true
# Error: allowed_origins = ["*"]
# Fix:
allowed_origins = ["https://app.example.com"]