ResourceDependency

Enum ResourceDependency 

Source
pub enum ResourceDependency {
    Simple(String),
    Detailed(Box<DetailedDependency>),
}
Expand description

A resource dependency specification supporting multiple formats.

Dependencies can be specified in two main formats to balance simplicity with flexibility. The enum uses Serde’s untagged attribute to automatically deserialize the correct variant based on the TOML structure.

§Variants

§Simple Dependencies

For local file dependencies, just specify the path directly:

[agents]
local-helper = "../shared/agents/helper.md"
nearby-agent = "./local/custom-agent.md"

§Detailed Dependencies

For remote dependencies or when you need more control:

[agents]
# Remote dependency with version
code-reviewer = { source = "official", path = "agents/reviewer.md", version = "v1.0.0" }

# Remote dependency with git reference
experimental = { source = "community", path = "agents/new.md", git = "develop" }

# Local dependency with explicit path (equivalent to simple form)
local-tool = { path = "../tools/agent.md" }

§Validation Rules

  • Local dependencies (no source): Cannot have version constraints
  • Remote dependencies (with source): Must have either version or git field
  • Path field: Required and cannot be empty
  • Source field: Must reference an existing source in the [sources] section

§Type Safety

The enum ensures type safety at compile time while providing runtime validation through the Manifest::validate method.

§Serialization Behavior

  • Simple paths serialize directly as strings
  • Detailed specs serialize as TOML inline tables
  • Empty optional fields are omitted for cleaner output
  • Deserialization is automatic based on TOML structure

§Memory Layout

This enum uses #[serde(untagged)] for automatic variant detection, which means deserialization tries the Detailed variant first, then falls back to Simple. This is efficient for the expected usage patterns where detailed dependencies are more common in larger projects.

§Memory Layout

The Detailed variant is boxed to reduce the size of the enum from 264 bytes to 24 bytes, improving memory efficiency when many dependencies are stored.

Variants§

§

Simple(String)

Simple path-only dependency, typically for local files.

This variant represents the simplest dependency format where only a file path is specified. It’s primarily used for local dependencies that exist in the filesystem relative to the project.

§Format

dependency-name = "path/to/file.md"

§Examples

[agents]
# Relative paths from manifest directory
helper = "../shared/helper.md"
custom = "./local/custom.md"

# Absolute paths (not recommended)
system = "/usr/local/share/agent.md"

§Limitations

  • Cannot specify version constraints
  • Cannot reference remote Git sources
  • Must be a valid filesystem path
  • Path must exist at installation time
§

Detailed(Box<DetailedDependency>)

Detailed dependency specification with full control.

This variant provides complete control over dependency specification, supporting both local and remote dependencies with version constraints, Git references, and explicit source mapping.

See DetailedDependency for field-level documentation.

Note: This variant is boxed to reduce the overall size of the enum.

Implementations§

Source§

impl ResourceDependency

Source

pub fn get_source(&self) -> Option<&str>

Get the source repository name if this is a remote dependency.

Returns the source name for remote dependencies (those that reference a Git repository), or None for local dependencies (those that reference local filesystem paths).

§Examples
use agpm_cli::manifest::{ResourceDependency, DetailedDependency};

// Local dependency - no source
let local = ResourceDependency::Simple("../local/file.md".to_string());
assert!(local.get_source().is_none());

// Remote dependency - has source
let remote = ResourceDependency::Detailed(Box::new(DetailedDependency {
    source: Some("official".to_string()),
    path: "agents/tool.md".to_string(),
    version: Some("v1.0.0".to_string()),
    branch: None,
    rev: None,
    command: None,
    args: None,
    target: None,
    filename: None,
    dependencies: None,
    tool: Some("claude-code".to_string()),
    flatten: None,
    install: None,
}));
assert_eq!(remote.get_source(), Some("official"));
§Use Cases

This method is commonly used to:

  • Determine if dependency resolution should use Git vs filesystem
  • Validate that referenced sources exist in the manifest
  • Filter dependencies by type (local vs remote)
  • Generate dependency graphs and reports
Source

pub fn get_target(&self) -> Option<&str>

Get the custom target directory for this dependency.

Returns the custom target directory if specified, or None if the dependency should use the default installation location for its resource type.

§Examples
use agpm_cli::manifest::{ResourceDependency, DetailedDependency};

// Dependency with custom target
let custom = ResourceDependency::Detailed(Box::new(DetailedDependency {
    source: Some("official".to_string()),
    path: "agents/tool.md".to_string(),
    version: Some("v1.0.0".to_string()),
    target: Some("custom/tools".to_string()),
    branch: None,
    rev: None,
    command: None,
    args: None,
    filename: None,
    dependencies: None,
    tool: Some("claude-code".to_string()),
    flatten: None,
    install: None,
}));
assert_eq!(custom.get_target(), Some("custom/tools"));

// Dependency without custom target
let default = ResourceDependency::Simple("../local/file.md".to_string());
assert!(default.get_target().is_none());
Source

pub fn get_tool(&self) -> Option<&str>

Get the tool for this dependency.

Returns the tool string if specified, or None if not specified. When None is returned, the caller should apply resource-type-specific defaults.

§Returns
  • Some(tool) if tool is explicitly specified
  • None if no tool is configured (use resource-type default)
Source

pub fn get_filename(&self) -> Option<&str>

Get the custom filename for this dependency.

Returns the custom filename if specified, or None if the dependency should use the default filename based on the dependency key.

§Examples
use agpm_cli::manifest::{ResourceDependency, DetailedDependency};

// Dependency with custom filename
let custom = ResourceDependency::Detailed(Box::new(DetailedDependency {
    source: Some("official".to_string()),
    path: "agents/tool.md".to_string(),
    version: Some("v1.0.0".to_string()),
    filename: Some("ai-assistant.md".to_string()),
    branch: None,
    rev: None,
    command: None,
    args: None,
    target: None,
    dependencies: None,
    tool: Some("claude-code".to_string()),
    install: None,
    flatten: None,
}));
assert_eq!(custom.get_filename(), Some("ai-assistant.md"));

// Dependency without custom filename
let default = ResourceDependency::Simple("../local/file.md".to_string());
assert!(default.get_filename().is_none());
Source

pub fn get_flatten(&self) -> Option<bool>

Get the flatten flag for this dependency.

Returns the flatten setting if explicitly specified, or None if the dependency should use the default flatten behavior based on tool configuration.

When flatten = true: Only the filename is used (e.g., nested/dir/file.mdfile.md) When flatten = false: Full path is preserved (e.g., nested/dir/file.mdnested/dir/file.md)

§Default Behavior (from tool configuration)
  • Agents: Default to true (flatten)
  • Commands: Default to true (flatten)
  • All others: Default to false (preserve structure)
Source

pub fn get_install(&self) -> Option<bool>

Get the install flag for this dependency.

Returns the install setting if explicitly specified, or None to use the default behavior (install = true).

When install = false: Dependency is resolved and content made available in template context, but file is not written to disk.

When install = true (or None): Dependency is installed as a file.

§Returns
  • Some(false) - Do not install the file, only make content available
  • Some(true) - Install the file normally
  • None - Use default behavior (install = true)
Source

pub fn get_path(&self) -> &str

Get the path to the resource file.

Returns the path component of the dependency, which is interpreted differently based on whether this is a local or remote dependency:

  • Local dependencies: Filesystem path relative to the manifest directory
  • Remote dependencies: Path within the Git repository
§Examples
use agpm_cli::manifest::{ResourceDependency, DetailedDependency};

// Local dependency - filesystem path
let local = ResourceDependency::Simple("../shared/helper.md".to_string());
assert_eq!(local.get_path(), "../shared/helper.md");

// Remote dependency - repository path
let remote = ResourceDependency::Detailed(Box::new(DetailedDependency {
    source: Some("official".to_string()),
    path: "agents/code-reviewer.md".to_string(),
    version: Some("v1.0.0".to_string()),
    branch: None,
    rev: None,
    command: None,
    args: None,
    target: None,
    filename: None,
    dependencies: None,
    tool: Some("claude-code".to_string()),
    flatten: None,
    install: None,
}));
assert_eq!(remote.get_path(), "agents/code-reviewer.md");
§Path Resolution

The returned path should be processed appropriately based on the dependency type:

  • Local paths may need resolution against the manifest directory
  • Remote paths are used directly within the cloned repository
  • All paths should use forward slashes (/) for cross-platform compatibility
Source

pub fn is_pattern(&self) -> bool

Check if this is a pattern-based dependency.

Returns true if this dependency uses a glob pattern to match multiple resources, false if it specifies a single resource path.

Patterns are detected by the presence of glob characters (*, ?, [) in the path field.

Source

pub fn get_version(&self) -> Option<&str>

Get the version constraint for dependency resolution.

Returns the version constraint that should be used when resolving this dependency from a Git repository. For local dependencies, always returns None.

§Priority Rules

If both version and git fields are present in a detailed dependency, the git field takes precedence:

use agpm_cli::manifest::{ResourceDependency, DetailedDependency};

let dep = ResourceDependency::Detailed(Box::new(DetailedDependency {
    source: Some("repo".to_string()),
    path: "file.md".to_string(),
    version: Some("v1.0.0".to_string()),  // This is ignored
    branch: Some("develop".to_string()),   // This takes precedence over version
    rev: None,
    command: None,
    args: None,
    target: None,
    filename: None,
    dependencies: None,
    tool: Some("claude-code".to_string()),
    flatten: None,
    install: None,
}));

assert_eq!(dep.get_version(), Some("develop"));
§Examples
use agpm_cli::manifest::{ResourceDependency, DetailedDependency};

// Local dependency - no version
let local = ResourceDependency::Simple("../local/file.md".to_string());
assert!(local.get_version().is_none());

// Remote dependency with version
let versioned = ResourceDependency::Detailed(Box::new(DetailedDependency {
    source: Some("repo".to_string()),
    path: "file.md".to_string(),
    version: Some("v1.0.0".to_string()),
    branch: None,
    rev: None,
    command: None,
    args: None,
    target: None,
    filename: None,
    dependencies: None,
    tool: Some("claude-code".to_string()),
    flatten: None,
    install: None,
}));
assert_eq!(versioned.get_version(), Some("v1.0.0"));

// Remote dependency with branch reference
let branch_ref = ResourceDependency::Detailed(Box::new(DetailedDependency {
    source: Some("repo".to_string()),
    path: "file.md".to_string(),
    version: None,
    branch: Some("main".to_string()),
    rev: None,
    command: None,
    args: None,
    target: None,
    filename: None,
    dependencies: None,
    tool: Some("claude-code".to_string()),
    flatten: None,
    install: None,
}));
assert_eq!(branch_ref.get_version(), Some("main"));
§Version Formats

Supported version constraint formats include:

  • Semantic versions: "v1.0.0", "1.2.3"
  • Semantic version ranges: "^1.0.0", "~2.1.0"
  • Branch names: "main", "develop", "latest", "feature/new"
  • Git tags: "release-2023", "stable"
  • Commit SHAs: "a1b2c3d4e5f6..."
Source

pub fn is_local(&self) -> bool

Check if this is a local filesystem dependency.

Returns true if this dependency refers to a local file (no Git source), or false if it’s a remote dependency that will be resolved from a Git repository.

This is a convenience method equivalent to self.get_source().is_none().

§Examples
use agpm_cli::manifest::{ResourceDependency, DetailedDependency};

// Local dependency
let local = ResourceDependency::Simple("../local/file.md".to_string());
assert!(local.is_local());

// Remote dependency
let remote = ResourceDependency::Detailed(Box::new(DetailedDependency {
    source: Some("official".to_string()),
    path: "agents/tool.md".to_string(),
    version: Some("v1.0.0".to_string()),
    branch: None,
    rev: None,
    command: None,
    args: None,
    target: None,
    filename: None,
    dependencies: None,
    tool: Some("claude-code".to_string()),
    flatten: None,
    install: None,
}));
assert!(!remote.is_local());

// Local detailed dependency (no source specified)
let local_detailed = ResourceDependency::Detailed(Box::new(DetailedDependency {
    source: None,
    path: "../shared/tool.md".to_string(),
    version: None,
    branch: None,
    rev: None,
    command: None,
    args: None,
    target: None,
    filename: None,
    dependencies: None,
    tool: Some("claude-code".to_string()),
    flatten: None,
    install: None,
}));
assert!(local_detailed.is_local());
§Use Cases

This method is useful for:

  • Choosing between filesystem and Git resolution strategies
  • Validation logic (local deps can’t have versions)
  • Installation planning (local deps don’t need caching)
  • Progress reporting (different steps for local vs remote)

Trait Implementations§

Source§

impl Clone for ResourceDependency

Source§

fn clone(&self) -> ResourceDependency

Returns a duplicate of the value. Read more
1.0.0 · Source§

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

Performs copy-assignment from source. Read more
Source§

impl Debug for ResourceDependency

Source§

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

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

impl<'de> Deserialize<'de> for ResourceDependency

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 ResourceDependency

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<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> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

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

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: 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: 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> Same for T

Source§

type Output = T

Should always be Self
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<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
Source§

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

Source§

impl<T> ErasedDestructor for T
where T: 'static,