Repository navigation
architecture: rethink config loading system and config files #774
Description
Problem
Mecatl's configuration system has grown from several legitimate needs, but its current ownership model is difficult to reason about:
- command roots parse flags and some environment/auth-file inputs;
app.Buildconstructs and reads/resolves operator settings throughpermconfig;- per-workspace, trust-gated project configuration must resolve after a session workspace is known;
- provider and MCP credentials have different loading/lifecycle seams;
- some settings are load-time snapshots while others are re-resolved or refreshed.
This makes it unclear which settings are process-static, which can safely become live-reloadable, and where a Kubernetes/database-backed configuration source should attach.
Goal
Design a coherent configuration architecture that separates:
- source acquisition — CLI flags, environment, operator files, auth files, Kubernetes ConfigMaps/Secrets, database/remote sources;
- process-wide operator resolution — typed validation and explicit per-field precedence/merge policy;
- workspace/session resolution — trust-gated project settings that must remain dependent on a workspace root;
- runtime composition —
app.Buildconsumes resolved configuration and injected resolvers/loaders rather than owning file-source selection.
The design must classify each configuration subtree as one of:
- process-static / restart required;
- reloadable atomically at runtime;
- per-session/per-workspace resolved;
- credential lifecycle-managed.
It should define safe live-reload semantics: validation before swap, last-known-good behavior, diagnostics, atomicity, which resources are rebuilt or retained, and security/trust constraints. It must preserve existing non-generic merge policies such as deny dominance, operator-only settings, CLI precedence, secret separation, and provider endpoint precedence.
Non-goals
- Replacing the system opportunistically inside the operator-defined-provider PR.
- A generic YAML overlay that erases security/trust-specific merge rules.
- Making secrets available in ordinary
settings.yaml. - Claiming every setting can be live reloaded.
Starting evidence
internal/adapter/permconfigcombines user-global/operator and per-workspace project configuration.internal/app.Buildconstructs the resolver and folds several operator subtrees.internal/cliconfigresolves command-side flags, environment, auth-file snapshots, and profile loaders.- Provider profile loading now has an injected composition seam, while MCP already has a profile-loader/lifecycle seam.
docs/configuration-reference.mddocuments schema keys, but not a cross-root effective-configuration or reloadability model.
Related
- docs: explain configuration ownership and defaults across mecated and mecatui #771 — mecated/mecatui configuration ownership and defaults
- docs: add a cross-product settings guide to the user-facing site #772 — user-facing cross-product settings guide
- ADR 0016 — multi-provider composition
- ADR 0237 — operator-defined LLM providers
Activity
jbeda commentedon Aug 26, 2026
Concrete symptom: composition downcasts a policy resolver for operator settings
internal/app.ConfigstorespermResolveras the intentionally narrowpermpolicy.RuleResolver, because the permission-policy consumer should only resolve workspace rules.app.Buildthen repeatedly downcasts it back to*permconfig.Resolverto access unrelated operator settings, for example provider definitions/overrides atinternal/app/build.go:1431.The assertion is guarded and works in production because Build constructs that concrete resolver, but it is a sign that one object is serving two contracts:
Do not widen
permpolicy.RuleResolverwith unrelated configuration accessors. The redesign should provide separate views over one underlying concrete source:An interim implementation could retain a concrete operator-resolver reference inside
internal/app; the longer-term source abstraction should permit file, Kubernetes, database, or remote operator configuration withoutapp.Builddowncasts.jbeda commentedon Oct 28, 2026
Additional configuration/composition cleanup evidence
Reviewing MCP credential resolution in PR #2583 exposed another instance of the ownership problem tracked here:
app.Config.permResolverstores the settings resolver as the narrowpermpolicy.RuleResolverinterface, even though composition needs the wider operator-settings object.buildPermResolverconstructs a concrete*permconfig.Resolver, narrows it on return, and composition then repeatedly asserts it back to that concrete type to access provider definitions, credential-store configuration, MCP configuration, model routing, learning, retention, harness context, and other operator settings.internal/app. A representative example isinternal/app/build.go:1855at PR head538bfa59c54bedf069a0efbbb8150678574797f9.Suggested cleanup within this architecture work
Retain the wider concrete settings resolver at the composition layer, preferably with a name such as
settingsResolver, and narrow it topermpolicy.RuleResolveronly at permission-policy and child-resolver boundaries. Do not widen the permission interface with unrelated operator-settings methods, and do not introduce another resolver/cache or settings-discovery pass.Preserve these constraints:
This is follow-up work for #774, not scope to fold into the MCP credential PR. The current MCP implementation does not depend on this cleanup for correctness.