pub struct SubAgentDef {
pub name: String,
pub description: String,
pub model: Option<ModelSpec>,
pub tools: ToolPolicy,
pub disallowed_tools: Vec<String>,
pub permissions: SubAgentPermissions,
pub skills: SkillFilter,
pub system_prompt: String,
pub hooks: SubagentHooks,
pub memory: Option<MemoryScope>,
pub source: Option<String>,
pub file_path: Option<PathBuf>,
}Fields§
§name: String§description: String§model: Option<ModelSpec>§tools: ToolPolicy§disallowed_tools: Vec<String>Additional denylist applied after the base tools policy.
Populated from tools.except in YAML frontmatter. Deny wins: tools listed
here are blocked even when they appear in tools.allow.
§Serde asymmetry (IMP-CRIT-04)
Deserialization reads this field from the nested tools.except key in YAML/TOML
frontmatter. Serialization (via #[derive(Serialize)]) writes it as a flat
top-level disallowed_tools key — not under tools. Round-trip serialization
is therefore not supported: a serialized SubAgentDef cannot be parsed back
as a valid frontmatter file. This is intentional for the current MVP but must
be addressed before v1.0.0 (see GitHub issue filed under IMP-CRIT-04).
permissions: SubAgentPermissions§skills: SkillFilter§system_prompt: String§hooks: SubagentHooksPer-agent hooks (PreToolUse / PostToolUse) from frontmatter.
Hooks are only honored for project-level and CLI-level definitions. User-level definitions (~/.zeph/agents/) have hooks stripped on load.
memory: Option<MemoryScope>Persistent memory scope. When set, a memory directory is created at spawn time
and MEMORY.md content is injected into the system prompt.
source: Option<String>Scope label and filename of the definition file (populated by load / load_all).
Stored as "<scope>/<filename>" (e.g., "project/my-agent.md").
The full absolute path is intentionally not stored to avoid leaking local
filesystem layout in diagnostics and /agent list output.
file_path: Option<PathBuf>Full filesystem path of the definition file (populated by load_with_boundary).
Used internally by edit/delete operations. Not included in diagnostics output.
Implementations§
Source§impl SubAgentDef
impl SubAgentDef
Sourcepub fn parse(content: &str) -> Result<Self, SubAgentError>
pub fn parse(content: &str) -> Result<Self, SubAgentError>
Parse a sub-agent definition from its frontmatter+markdown content.
The primary format uses YAML frontmatter delimited by ---:
---
name: my-agent
description: Does something useful
model: claude-sonnet-4-20250514
tools:
allow:
- shell
permissions:
max_turns: 10
skills:
include:
- "git-*"
---
You are a helpful agent.TOML frontmatter (+++) is supported as a deprecated fallback and will emit a
tracing::warn! message. It will be removed in v1.0.0.
§Errors
Returns SubAgentError::Parse if the frontmatter delimiters are missing or the
content is malformed, and SubAgentError::Invalid if required fields are empty or
tools.allow and tools.deny are both specified.
Sourcepub fn load(path: &Path) -> Result<Self, SubAgentError>
pub fn load(path: &Path) -> Result<Self, SubAgentError>
Load a single definition from a .md file.
When boundary is provided, the file’s canonical path must start with
boundary — this rejects symlinks that escape the allowed directory.
§Errors
Returns SubAgentError::Parse if the file cannot be read, exceeds 256 KiB,
escapes the boundary via symlink, or fails to parse.
Sourcepub fn load_all(paths: &[PathBuf]) -> Result<Vec<Self>, SubAgentError>
pub fn load_all(paths: &[PathBuf]) -> Result<Vec<Self>, SubAgentError>
Load all definitions from a list of paths (files or directories).
Paths are processed in order; when two entries share the same agent
name, the first one wins (higher-priority path takes precedence).
Non-existent directories are silently skipped.
For directory entries from user/extra dirs: parse errors are warned and skipped.
For CLI file entries (is_cli_source = true): parse errors are hard failures.
§Errors
Returns SubAgentError if a CLI-sourced .md file fails to parse.
Sourcepub fn load_all_with_sources(
ordered_paths: &[PathBuf],
cli_agents: &[PathBuf],
config_user_dir: Option<&PathBuf>,
extra_dirs: &[PathBuf],
) -> Result<Vec<Self>, SubAgentError>
pub fn load_all_with_sources( ordered_paths: &[PathBuf], cli_agents: &[PathBuf], config_user_dir: Option<&PathBuf>, extra_dirs: &[PathBuf], ) -> Result<Vec<Self>, SubAgentError>
Load all definitions with scope context for source tracking and security checks.
cli_agents — CLI paths (hard errors on parse failure, no boundary check).
config_user_dir — optional user-level dir override.
extra_dirs — extra dirs from config.
§Errors
Returns SubAgentError if a CLI-sourced .md file fails to parse.
Source§impl SubAgentDef
impl SubAgentDef
Sourcepub fn serialize_to_markdown(&self) -> String
pub fn serialize_to_markdown(&self) -> String
Serialize the definition to YAML frontmatter + markdown body.
Uses WritableRawDef (with correct tools.except nesting) to avoid the
IMP-CRIT-04 serde asymmetry. The result can be re-parsed with SubAgentDef::parse.
§Panics
Panics if serde_norway serialization fails (should not happen for valid structs).
Sourcepub fn save_atomic(&self, dir: &Path) -> Result<PathBuf, SubAgentError>
pub fn save_atomic(&self, dir: &Path) -> Result<PathBuf, SubAgentError>
Write definition to {dir}/{self.name}.md atomically using temp+rename.
Creates parent directories if needed. Uses tempfile::NamedTempFile in the same
directory for automatic cleanup on failure.
§Errors
Returns SubAgentError::Invalid if the agent name fails validation (prevents path traversal).
Returns SubAgentError::Io if directory creation, write, or rename fails.
Sourcepub fn delete_file(path: &Path) -> Result<(), SubAgentError>
pub fn delete_file(path: &Path) -> Result<(), SubAgentError>
Delete a definition file from disk.
§Errors
Returns SubAgentError::Io if the file does not exist or cannot be removed.
Trait Implementations§
Source§impl Clone for SubAgentDef
impl Clone for SubAgentDef
Source§fn clone(&self) -> SubAgentDef
fn clone(&self) -> SubAgentDef
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for SubAgentDef
impl Debug for SubAgentDef
Source§impl<'de> Deserialize<'de> for SubAgentDef
impl<'de> Deserialize<'de> for SubAgentDef
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 SubAgentDef
impl RefUnwindSafe for SubAgentDef
impl Send for SubAgentDef
impl Sync for SubAgentDef
impl Unpin for SubAgentDef
impl UnsafeUnpin for SubAgentDef
impl UnwindSafe for SubAgentDef
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,
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 moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request