Skip to content

apomesh-config

apomesh-config is the daemon’s configuration surface: a typed Rust config (Config) that maps 1:1 to an operator-authored TOML file. The programmatic surface is the source of truth and TOML is the serialization — Config::builder is the canonical construction path, and Config::from_toml exists for operators who hand-author a config file. Both routes run Config::validate, so a cross-field mistake surfaces at load as a typed ConfigError rather than at first feature use. Touch this crate to add or change an operator-tunable knob the orchestrator or worker reads at boot.

  • Layer: auth / config / support — a workspace utility crate that sits beside the substrate layering, not inside it (like apomesh-auth-providers). It is a leaf both daemons and several support crates read at startup.
  • Depends on: apomesh-substrate — every section deserializes directly into substrate vocabulary (TenantId, ToolCategory, SecretForwardingHopPolicy, ModelSpec, ProviderCredential) rather than a parallel mirror shape. Plus serde + toml for the daemon config and serde_norway for the declarative provider YAML.
  • Consumed by: apomesh-orchestrator, apomesh-orchestrator-bin, apomesh-worker, apomesh-auth-providers (reads the [auth] block), and apomesh-reseal.

The daemon config root Config — one typed struct, one operator TOML file. Every section is #[serde(default)], so operators author only the fields they override; a missing section collapses to the substrate-shipped default.

SectionConfigures
[substrate]Global budget cap, cancel watchdog, per-tier LLM max-tokens, tool-loop iteration cap, Execute fan-out concurrency, native web-search provider, secret-forwarding hop policy
[auth]SessionAuth + WorkerAuth backend selection and per-backend blocks — consumed by apomesh-auth-providers
[statestore]StateStore backend (in-memory / sqlite / postgres / hybrid) + working-memory TTL
[routing]Stage-2 scoring weights, pick mode, cost-budget-aware gate
[server]Transport-boundary limits — gRPC message / stream / keepalive caps, REST body + SSE caps, CORS allow-origins
[a2a]The A2A well-known-card designation — the serving tenant + agent (and optional version pin) the public /.well-known/agent-card.json route serves; both absent-safe
[[mcp_servers]] · [mcp_sandbox] · [mcp_migration]MCP server registrations, the long-lived-subprocess sandbox knobs, and the first-boot store-seeding target tenant
[[cli_tools]]Operator-defined CLI tool templates registered at startup
[[extension_vendors]]Tier-4 extension-vendor allowlist (absent = unrestricted)
[[models]]Model-catalog overlay on the compiled seed — pricing, capabilities, per-class defaults
[tenants.<id>]Per-tenant config installed into the TenantRegistry at boot
[providers] · [observability]Reserved section placeholders (default-empty today)

Validation is at load, not first use. Config::validate runs every cross-field invariant — an oauth backend requires an [auth.oauth] block, a zero watchdog / iteration cap / Execute concurrency / server limit is rejected, [[mcp_servers]] and [[cli_tools]] names must be non-empty and unique, [[extension_vendors]] must be reverse-DNS, [[models]] entries must carry a unique (provider, id). A [mcp_servers.transport] kind = "http" block fails unless the crate is built with the mcp-http feature.

Provider config is a separate declarative YAML domain, also owned here (provider_import): a per-tenant document declaring providers, credentials, profiles, and models, projected into the durable config stores at boot. Secrets are referenced by env-var name, never inlined on the production path. It is selected by APOMESH_PROVIDER_CONFIG (single file — a named-but- unreadable path aborts boot) or APOMESH_PROVIDER_CONFIG_DIR (one <tenant>.yaml per tenant); unset yields the built-in dev default.

It does not own per-tenant runtime state — once seeded, credentials, models, and MCP servers become authoritative in the durable stores, not the TOML — nor deploy-profile selection, which is a deploy/local convention (APOMESH_PROFILE), not a config field.

  • Config — the daemon config root; maps 1:1 to the operator TOML.
  • Config::from_toml / from_toml_str — read → parse → validate; surfaces I/O, parse, and validation errors as ConfigError.
  • Config::builderConfigBuilder — the canonical programmatic construction path; .build() runs the same validation.
  • Config::validate — the single cross-field invariant hook; a violation is ConfigError::Validation, aborting boot.
  • Config::model_catalog — builds the deployment ModelSpecCatalog by overlaying [[models]] onto the compiled seed; a bad overlay aborts boot rather than mis-billing a dispatch.
  • ConfigError — the load/validate error vocabulary (Io, Parse, Validation, Catalog, LlmConfigStore).
  • select_provider_config / PROVIDER_CONFIG_ENV — the strict provider-YAML selection described above.

A minimal config authors only what overrides a default; the daemon reads it from the APOMESH_CONFIG env var:

/etc/apomesh/config.toml
[auth]
backend = "none" # none | oauth | api-key | mtls
[statestore.backend]
kind = "hybrid"
postgres_url = "postgres://apomesh@postgres:5432/apomesh"
redis_url = "redis://redis:6379"
[substrate.global_cap]
tokens = 10_000_000
Terminal window
# apomesh-orchestrator-bin and apomesh-worker both read APOMESH_CONFIG.
APOMESH_CONFIG=/etc/apomesh/config.toml apomesh-orchestrator

At startup the binary calls Config::from_toml(path) — read the file, parse the TOML, run validate — before wiring any subsystem. An unset APOMESH_CONFIG boots on Config::default(), the substrate-shipped defaults. Either way a malformed config fails the daemon at startup, not mid-session.