Expand description
The machine-config settings screen: which agent each role resolves to, and a safe way to change those assignments.
Reading goes through Config::load_layers like every other consumer, so
the screen shows what a run started now would see. Writing touches one
file, the machine layer, whose path is resolved here from
Config::machine_layer (or injected by a test) and never taken from the
client - a repository’s magi.toml cannot become a write target.
toml_edit is not a dependency, so the write is a line-level patch of the
[roles] table: every byte outside the keys being changed (comments,
[vars], Tera expressions, other tables) is carried over untouched. The
patch is only a proposal. It is written to a temporary file beside the
original, the layered config is re-loaded with that file standing in for
the machine layer, and the result must say exactly what was asked for
before the original is replaced by a rename. Anything the line patcher
cannot place (an inline roles = { .. }, say) fails that check and is
refused with a readable message instead of being guessed at.
The machine file applies to every repository, so two more rules hold. The
detected roster is never written down (Config::load_layers fills agents
from PATH whenever no layer declares the key), so a role save adds no
second [[agents]] declaration and CLIs installed later are still found.
And a save is also loaded against every other checkout found under
[repos] roots: one that loaded before and would not now (it declares the
same roles.* key) refuses the save in words. Limits: checkouts outside
roots are not checked, a checkout already broken is ignored, and another
process editing a repo config between the check and the rename is not
prevented. The view shows the same lock up front.