- Status: Accepted
- Date: 2026-03-07
- Owners: OpenClaw maintainers
- Related roadmap items:
R139, phase-2 follow-up completed 2026-03-19
OpenClaw currently has distributed configuration logic across config.py, services/runtime_config.py, and selected call sites that still read env vars directly. This increases precedence drift risk and makes behavior harder to reason about.
The unification work required a phased, backward-compatible rollout rather than a single destructive rewrite.
Adopt one authoritative layered model for runtime LLM config resolution, exposed through a unified resolver and then through a single effective-config facade consumed by compatibility APIs and downstream readers.
Layer precedence (highest to lowest):
env(OPENCLAW_*first,MOLTBOT_*fallback)runtime_override(in-memory only; process-local)persisted(OPENCLAW_STATE_DIR/config.json)default
Key points:
- Keep env-first semantics for operational safety and backward compatibility.
- Preserve legacy key support with explicit warning behavior.
- Keep runtime overrides non-persisted and source-attributed.
Positive:
- Deterministic precedence and source attribution.
- Reduced duplicated merge logic in primary runtime paths.
- Safer phased migration with compatibility facade intact.
- Shared read seams make parity testing and future deprecation work narrower.
Trade-offs:
- Temporary coexistence of migrated and non-migrated call sites during phased rollout.
- Additional adapter code until follow-up phases complete.
Phase 1 (R139):
- Introduce unified resolver + runtime override registry.
- Refactor
services/runtime_config.pyeffective-read path to resolver-backed flow. - Migrate core LLM call sites to stop duplicating env precedence.
- Add precedence/compatibility regression tests.
Phase 2 (completed 2026-03-19):
- Introduced
services/effective_config.pyas the supported effective-config read facade. - Migrated remaining mixed-path readers touched by the phase onto the shared facade/compatibility shims.
- Added parity coverage so env/runtime/persisted/default precedence is asserted once at the shared seam instead of at each consumer.
Future follow-ups:
- Continue migrating any remaining direct env readers that still overlap with the runtime config contract.
- Remove obsolete adapter/shim code once migration reaches stable completion.
- Big-bang rewrite of all config readers:
- Rejected due to blast radius and rollback difficulty.
- Keep dual systems and patch ad hoc:
- Rejected due to ongoing precedence drift and maintenance cost.