pub struct Config {}Expand description
Top-level configuration.
Fields§
§agents: Vec<AgentSpec>Agent roster.
roles: RolesRole assignment.
graph: GraphGraph shape.
blind: BlindBlindness policy.
verify: VerifyVerification commands.
disk: DiskDisk hygiene.
merge: MergeMerge policy.
update: UpdateSelf-update policy.
prompts: PromptsProject-specific text appended to the node prompts.
notify: NotifyHow the operator is told a run is waiting on them.
repos: ReposLocal repositories the plan surface can start or derive a conversation against.
talk: TalkPolicy for the standing conversation (crate::talk).
daemon: DaemonHow many runs magi serve’s own loop drives at once.
Implementations§
Source§impl Config
impl Config
Sourcepub const CONFIG_DIR_ENV: &str = "MAGI_CONFIG_DIR"
pub const CONFIG_DIR_ENV: &str = "MAGI_CONFIG_DIR"
Environment variable that relocates the machine-wide config layer.
Set it to a directory and magi reads <dir>/magi/config.toml instead
of the one under dirs::config_dir; set it to the empty string and
magi reads no machine layer at all.
This exists because the machine layer is otherwise unavoidable, and a
test that builds a config fixture is not asking for the operator’s
preferences to be merged into it. Adding [repos] roots to the real
machine config on a development box turned two passing tests red -
repos_list_returns_name_and_path_for_every_configured_root and
repos_list_only_rescans_within_the_ttl_when_asked_to, whose fixtures
declare [repos] roots of their own, which Config::layers then
found in two layers and Config::refuse_split_arrays correctly
refused. CI never saw it: a runner has no machine config, so the suite
was green there and red only where somebody actually uses magi.
An operator gets the same escape hatch for free: a second machine config, or none, without moving files about.
Sourcepub fn load(path: &Path) -> Result<Self>
pub fn load(path: &Path) -> Result<Self>
Load one file through teravars: Tera rendering, [vars] resolution,
and the include = [...] directive.
Sourcepub fn load_layers(paths: &[PathBuf]) -> Result<Self>
pub fn load_layers(paths: &[PathBuf]) -> Result<Self>
Load and deep-merge a stack of config files, later files winning.
This is why the config is TOML-through-teravars rather than plain serde:
the roster is a machine fact (which CLIs and plans you pay for) while
the gate is a repository fact (cargo make check here, pnpm test
there). Picking one file and ignoring the other would force every repo
to restate the roster.
Sourcepub fn array_provenance(
paths: &[PathBuf],
key: &str,
) -> Vec<(PathBuf, Vec<String>)>
pub fn array_provenance( paths: &[PathBuf], key: &str, ) -> Vec<(PathBuf, Vec<String>)>
Which layers contributed to a composed, appendable array key (e.g.
"verify.gate"), in the same low-to-high-priority order
Config::load_layers concatenates them in. Layers that do not
declare key at all are omitted.
This is a display aid for magi doctor only. The command list
that actually runs always comes from the one joint
teravars::load_merged call in load_layers, never from this
function - the exact hazard Config::refuse_split_arrays warns
about is two merge paths that might disagree, so this function must
never become a second source of the composed value, only of which
file wrote which line in it.
Re-rendering each layer alone can, in principle, resolve a
{{ vars.x }} differently than the joint render would, if x is
defined in one layer and referenced in another - the same caveat
refuse_split_arrays’s structural, key-only check already lives with.
None of magi’s own gate commands cross that line, and a doctor listing
is read by a human who can compare it against the joint one printed
alongside it, so this is judged worth the simplicity of not
threading provenance through the real load path.
Sourcepub fn describe_composed(
paths: &[PathBuf],
commands: &[String],
key: &str,
empty: &str,
) -> String
pub fn describe_composed( paths: &[PathBuf], commands: &[String], key: &str, empty: &str, ) -> String
Render a composed command list for magi doctor: the joined command
line the run actually uses, plus - only when more than one layer
contributed - which layer wrote which line.
A single contributing layer (the common case today) stays the plain
one-line summary magi has always printed, empty included: that
honest “(none — …)” is what caught a real gate-composition gap
before this array could compose at all, and composition should not
make the common case noisier.
Sourcepub fn discover(
repo: &Path,
explicit: Option<&Path>,
) -> Result<(Self, Vec<PathBuf>)>
pub fn discover( repo: &Path, explicit: Option<&Path>, ) -> Result<(Self, Vec<PathBuf>)>
Resolve the config for repo, honouring an explicit --config path.
Returns the config and the layers it came from, empty for built-in defaults.
Sourcepub fn layers(repo: &Path) -> Vec<PathBuf>
pub fn layers(repo: &Path) -> Vec<PathBuf>
Every config layer that applies to repo, in increasing precedence.
The machine layer is whatever Config::machine_layer resolves to,
which is nothing at all in a test build.
Sourcepub fn autodetected() -> Self
pub fn autodetected() -> Self
Built-in config whose roster is the agent CLIs found on PATH.
Sourcepub fn cache_dir(&self) -> Option<PathBuf>
pub fn cache_dir(&self) -> Option<PathBuf>
The shared build cache the verify commands and the agents both build
into, when the config declares one. See Verify::cache_dir.
Sourcepub fn resolve_roles(&self) -> Result<ResolvedRoles>
pub fn resolve_roles(&self) -> Result<ResolvedRoles>
Fill the roles out to the configured widths.
An empty role list rotates through the whole roster, so a three-agent
roster with candidates = 3 gives one implementation per agent, and
judges = 3 rotates the judge seats by one so that judge i is not the
author of candidate i whenever the roster has more than one agent.
Sourcepub fn starter_toml() -> String
pub fn starter_toml() -> String
Starter config, as written by magi init.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Config
impl<'de> Deserialize<'de> for Config
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for Config
impl RefUnwindSafe for Config
impl Send for Config
impl Sync for Config
impl Unpin for Config
impl UnsafeUnpin for Config
impl UnwindSafe for Config
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more