Profile planning for library hosts
The additive document API plans profiles from supplied documents and controls.
Profiles.plan never discovers files, reads the process environment, executes
project code, or resolves secrets. Pass the environment map explicitly.
Call the planner before reading profile candidates. Read only candidates whose
SourceIdentity.Profile appears in the successful plan’s Active list. Keep
inactive candidates unread, including invalid files. ProfileSelection.Disabled
returns an empty disabled plan without interpreting profile controls.
Selecting profiles
The selector has this order of authority:
ProfileSelection.Namessupplied by the host.- A present
MORPHIR_PROFILESenvironment entry, including an empty value. - The discovered root primary documents’ active selector.
- The discovered root primary documents’ default selector.
There is no implicit CI or default profile. A comma-separated environment
selector trims names. A present whitespace-only environment selector disables
profiles and suppresses includes and file loading. An explicit Names [] selector
still permits base includes.
CSV trimming uses ASCII space, tab, newline, carriage return, vertical tab, and
form feed. Empty CSV elements fail validation. Values such as dev,,metrics or
dev, do not silently discard an empty name.
The legacy CiProfileMode API retains its separate behavior.
Control ownership and ordering
Only discovered root primary documents own activation controls. A root primary that is also explicitly selected keeps its original control authority, while its ordinary values contribute once at the selected-file layer. Machine, member, arbitrary selected, user, and profile documents cannot activate profiles. The planner reports invalid controls before the resolver filters ownership subtrees.
profiles.include expands before selected roots. Groups emit their own name
before expanding members depth first, and duplicate names keep their last
occurrence. A higher group definition replaces the whole
lower definition. Enabled processing checks the entire declared group graph,
including inactive groups, for cycles and depth/expansion bounds. Names match
[a-z][a-z0-9_-]{0,63}. A graph contains at most 64 groups, each with at most 64
members and at most 32 group levels. The active plan contains at most 128 distinct
names. Host options may tighten depth and expansion bounds.
For example, profiles.groups.production = ["postgres", "metrics"] and
profiles.active = ["production"] activate production, postgres, then
metrics. A higher profiles.active = null fails control typing even if a lower
source supplied a valid list. Ordinary null overlay skipping does not apply to
profile controls.
Resolution applies each active name’s workspace documents before its member documents, using JSON/JSON5, then YAML/YML, then TOML. All files for the next active name follow all files for the previous name. Adjacent user overrides, environment values, and explicit host values follow profiles.
Diagnostics and integration
Inspect ProfilePlan.Diagnostics before reading any planned profile files.
Errors identify the declaring control’s source and key path. The resolver
retains winning origins separately from the control plan. An explicit host owns
the source inventory and workspace/member identity. The library does not infer
either from current directories or ambient environment state.
The qualification baseline is Moon-Lander
d6216c7469c045548cb15b3f9321857ac41d2cd0,
specifically pkgs/config/profile_types.mbt, pkgs/config/profiles/profiles.mbt,
and pkgs/config/profiles/control_layers.mbt. Its control merge keeps nulls until
validation, unlike ordinary configuration merging.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.