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.
Position in the workspace
Section titled “Position in the workspace”- 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. Plusserde+tomlfor the daemon config andserde_norwayfor the declarative provider YAML. - Consumed by:
apomesh-orchestrator,
apomesh-orchestrator-bin,
apomesh-worker,
apomesh-auth-providers (reads
the
[auth]block), andapomesh-reseal.
What it owns
Section titled “What it owns”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.
| Section | Configures |
|---|---|
[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.
Public surface
Section titled “Public surface”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 asConfigError.Config::builder→ConfigBuilder— the canonical programmatic construction path;.build()runs the same validation.Config::validate— the single cross-field invariant hook; a violation isConfigError::Validation, aborting boot.Config::model_catalog— builds the deploymentModelSpecCatalogby 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:
[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# apomesh-orchestrator-bin and apomesh-worker both read APOMESH_CONFIG.APOMESH_CONFIG=/etc/apomesh/config.toml apomesh-orchestratorAt 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.
Related
Section titled “Related”- Concepts: Identity & authorization —
the auth plane the
[auth]block selects a backend for. - Operate: The local stack — the two-homes config
model and the
dev/oauthprofile selector. - Reference:
apomesh-auth-providers (the
[auth]backends), apomesh-orchestrator-bin (the boot wiring that loads and validates the config).