Module manifest

Module manifest 

Source
Expand description

Manifest file parsing and validation for CCPM projects.

This module handles the ccpm.toml manifest file that defines project dependencies and configuration. The manifest uses TOML format and follows a structure similar to Cargo.toml, providing a lockfile-based dependency management system for Claude Code resources.

§Overview

The manifest system enables:

  • Declarative dependency management through ccpm.toml
  • Reproducible installations via lockfile generation
  • Support for multiple Git-based source repositories
  • Local and remote dependency resolution
  • Version constraint specification and validation
  • Cross-platform path handling and installation
  • MCP (Model Context Protocol) server configuration management
  • Atomic file operations for reliability

§Complete TOML Format Specification

§Basic Structure

A ccpm.toml manifest file consists of four main sections:

# Named source repositories (optional)
[sources]
# Git repository URLs mapped to convenient names
official = "https://github.com/example-org/ccpm-official.git"
community = "https://github.com/community/ccpm-resources.git"
private = "git@github.com:company/private-resources.git"

# Installation target directories (optional)
[target]
# Where agents should be installed (default: ".claude/agents")
agents = ".claude/agents"
# Where snippets should be installed (default: ".claude/ccpm/snippets")
snippets = ".claude/ccpm/snippets"
# Where commands should be installed (default: ".claude/commands")
commands = ".claude/commands"

# Agent dependencies (optional)
[agents]
# Various dependency specification formats
simple-agent = "../local/agents/helper.md"                    # Local path
remote-agent = { source = "official", path = "agents/reviewer.md", version = "v1.0.0" }
latest-agent = { source = "community", path = "agents/utils.md", version = "latest" }
branch-agent = { source = "private", path = "agents/internal.md", git = "develop" }
commit-agent = { source = "official", path = "agents/stable.md", git = "abc123..." }
# Custom target installation directory (relative to .claude)
custom-agent = { source = "official", path = "agents/special.md", version = "v1.0.0", target = "integrations/ai" }

# Snippet dependencies (optional)
[snippets]
# Same formats as agents
local-snippet = "../shared/snippets/common.md"
remote-snippet = { source = "community", path = "snippets/utils.md", version = "v2.1.0" }
# Custom target for special snippets
integration-snippet = { source = "community", path = "snippets/api.md", version = "v1.0.0", target = "tools/snippets" }

# Command dependencies (optional)
[commands]
# Same formats as agents and snippets
local-command = "../shared/commands/helper.md"
remote-command = { source = "community", path = "commands/build.md", version = "v1.0.0" }

§Sources Section

The [sources] section maps convenient names to Git repository URLs:

[sources]
# HTTPS URLs (recommended for public repositories)
official = "https://github.com/owner/ccpm-resources.git"
community = "https://gitlab.com/group/ccpm-community.git"

# SSH URLs (for private repositories with key authentication)
private = "git@github.com:company/private-resources.git"
internal = "git@gitlab.company.com:team/internal-resources.git"

# Local Git repository URLs
local-repo = "file:///absolute/path/to/local/repo"

# Environment variable expansion (useful for CI/CD)
dynamic = "https://github.com/${GITHUB_ORG}/resources.git"
home-repo = "file://${HOME}/git/resources"

§Target Section

The [target] section configures where resources are installed:

[target]
# Default values shown - these can be customized
agents = ".claude/agents"      # Where agent .md files are copied
snippets = ".claude/ccpm/snippets"  # Where snippet .md files are copied
commands = ".claude/commands"  # Where command .md files are copied

# Alternative configurations
agents = "resources/agents"
snippets = "resources/snippets"
commands = "resources/commands"

# Absolute paths are supported
agents = "/opt/claude/agents"
snippets = "/opt/claude/snippets"
commands = "/opt/claude/commands"

§Dependency Sections

Both [agents] and [snippets] sections support multiple dependency formats:

§1. Local Path Dependencies

For resources in your local filesystem:

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

# Absolute paths (not recommended for portability)
system-agent = "/usr/local/share/claude/agents/system.md"

Local dependencies:

  • Do not support version constraints
  • Are copied directly from the filesystem
  • Are not cached or managed through Git
  • Must exist at install time

§2. Remote Source Dependencies

For resources from Git repositories:

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

# Using latest version (not recommended for production)
utils = { source = "community", path = "agents/utils.md", version = "latest" }

# Specific Git branch
bleeding-edge = { source = "official", path = "agents/experimental.md", git = "develop" }

# Specific Git commit (maximum reproducibility)
stable = { source = "official", path = "agents/stable.md", git = "a1b2c3d4e5f6..." }

# Git tag (alternative to version field)
tagged = { source = "community", path = "agents/tagged.md", git = "release-2.0" }

§3. Custom Target Installation

Dependencies can specify a custom installation directory using the target field:

[agents]
# Install to .claude/integrations/ai/ instead of .claude/agents/
integration-agent = {
    source = "official",
    path = "agents/integration.md",
    version = "v1.0.0",
    target = "integrations/ai"
}

# Organize tools in a custom structure
debug-tool = {
    source = "community",
    path = "agents/debugger.md",
    version = "v2.0.0",
    target = "development/tools"
}

[snippets]
# Custom location for API snippets
api-helper = {
    source = "community",
    path = "snippets/api.md",
    version = "v1.0.0",
    target = "api/snippets"
}

Custom targets:

  • Are always relative to the .claude directory
  • Leading .claude/ or / are automatically stripped
  • Directories are created if they don’t exist
  • Help organize resources in complex projects

§4. Custom Filenames

Dependencies can specify a custom filename using the filename field:

[agents]
# Install as "ai-assistant.md" instead of "my-ai.md"
my-ai = {
    source = "official",
    path = "agents/complex-long-name-v2.md",
    version = "v1.0.0",
    filename = "ai-assistant.md"
}

# Change both filename and extension
doc-helper = {
    source = "community",
    path = "agents/documentation.md",
    version = "v2.0.0",
    filename = "docs.txt"
}

# Combine custom target and filename
special-tool = {
    source = "official",
    path = "agents/debug-analyzer-enhanced.md",
    version = "v1.0.0",
    target = "tools/debugging",
    filename = "analyzer.markdown"
}

[scripts]
# Rename script during installation
data-processor = {
    source = "community",
    path = "scripts/data-processor-v3.py",
    version = "v1.0.0",
    filename = "process.py"
}

Custom filenames:

  • Include the full filename with extension
  • Override the default name (based on dependency key)
  • Work with any resource type
  • Can be combined with custom targets

§Version Constraint Syntax

CCPM supports flexible version constraints:

  • "v1.0.0" - Exact semantic version
  • "1.0.0" - Exact version (v prefix optional)
  • "latest" - Always use the latest available version
  • "main" - Use the main/master branch HEAD
  • "develop" - Use a specific branch
  • "a1b2c3d4..." - Use a specific commit SHA
  • "release-1.0" - Use a specific Git tag

§Complete Examples

§Minimal Manifest

[agents]
helper = "../agents/helper.md"

§Production Manifest

[sources]
official = "https://github.com/claude-org/official-resources.git"
community = "https://github.com/claude-community/resources.git"
company = "git@github.com:mycompany/claude-resources.git"

[target]
agents = "resources/agents"
snippets = "resources/snippets"

[agents]
# Production agents with pinned versions
code-reviewer = { source = "official", path = "agents/code-reviewer.md", version = "v2.1.0" }
documentation = { source = "community", path = "agents/doc-writer.md", version = "v1.5.2" }
internal-helper = { source = "company", path = "agents/helper.md", version = "v1.0.0" }

# Local customizations
custom-agent = "./local/agents/custom.md"

[snippets]
# Utility snippets
common-patterns = { source = "community", path = "snippets/patterns.md", version = "v1.2.0" }
company-templates = { source = "company", path = "snippets/templates.md", version = "latest" }

§Security Considerations

CRITICAL: Never include authentication credentials in ccpm.toml:

# ❌ NEVER DO THIS - credentials will be committed to git
[sources]
private = "https://token:ghp_xxxx@github.com/company/repo.git"

# ✅ Instead, use global configuration in ~/.ccpm/config.toml
# Or use SSH keys with git@ URLs
[sources]
private = "git@github.com:company/repo.git"

Authentication should be configured globally in ~/.ccpm/config.toml or through SSH keys for git@ URLs. See crate::config for details.

§Relationship to Lockfile

The manifest works together with the lockfile (ccpm.lock):

  • Manifest (ccpm.toml): Declares dependencies and constraints
  • Lockfile (ccpm.lock): Records exact resolved versions and checksums

When you run ccpm install:

  1. Reads dependencies from ccpm.toml
  2. Resolves versions within constraints
  3. Generates/updates ccpm.lock with exact commits
  4. Installs resources to target directories

See crate::lockfile for lockfile format details.

§Cross-Platform Compatibility

CCPM handles platform differences automatically:

  • Path separators (/ vs \) are normalized
  • Home directory expansion (~) is supported
  • Environment variable expansion is available
  • Git commands work on Windows, macOS, and Linux
  • Long path support on Windows (>260 characters)
  • Unicode filenames and paths are fully supported

§Best Practices

  1. Use semantic versions: Prefer v1.0.0 over latest
  2. Pin production dependencies: Use exact versions in production
  3. Organize sources logically: Group by organization or purpose
  4. Document dependencies: Add comments explaining why each is needed
  5. Keep manifests simple: Avoid overly complex dependency trees
  6. Use SSH for private repos: More secure than HTTPS tokens
  7. Test across platforms: Verify paths work on all target systems
  8. Version control manifests: Always commit ccpm.toml to git
  9. Validate regularly: Run ccpm validate before commits
  10. Use lockfiles: Commit ccpm.lock for reproducible builds

§Error Handling

The manifest module provides comprehensive error handling with:

  • Context-rich errors: Detailed messages with actionable suggestions
  • Validation errors: Clear explanations of manifest problems
  • I/O errors: Helpful context for file system issues
  • TOML parsing errors: Specific syntax error locations
  • Security validation: Detection of potential security issues

All errors implement std::error::Error and provide both user-friendly messages and programmatic access to error details.

§Performance Characteristics

  • Parsing: O(n) where n is the manifest file size
  • Validation: O(d) where d is the number of dependencies
  • Serialization: O(n) where n is the total data size
  • Memory usage: Proportional to manifest complexity
  • Thread safety: All operations are thread-safe

§Integration with Other Modules

The manifest module works closely with other CCPM modules:

§With crate::resolver

use ccpm::manifest::Manifest;
use ccpm::resolver::DependencyResolver;

let manifest = Manifest::load(&project_path.join("ccpm.toml"))?;
let resolver = DependencyResolver::new(&manifest);
let resolved = resolver.resolve_all().await?;

§With crate::lockfile

use ccpm::manifest::Manifest;
use ccpm::lockfile::LockFile;

let manifest = Manifest::load(&project_path.join("ccpm.toml"))?;
let lockfile = LockFile::generate_from_manifest(&manifest).await?;
lockfile.save(&project_path.join("ccpm.lock"))?;

§With crate::git for Source Management

use ccpm::manifest::Manifest;
use ccpm::git::GitManager;

let manifest = Manifest::load(&project_path.join("ccpm.toml"))?;
let git = GitManager::new(&cache_dir);

for (name, url) in &manifest.sources {
    git.clone_or_update(name, url).await?;
}

Structs§

DetailedDependency
Detailed dependency specification with full control over source resolution.
Manifest
The main manifest file structure representing a complete ccpm.toml file.
TargetConfig
Target directories configuration specifying where resources are installed.

Enums§

ResourceDependency
A resource dependency specification supporting multiple formats.

Functions§

find_manifest
Find the manifest file by searching up the directory tree from the current directory.
find_manifest_from
Find the manifest file by searching up from a specific starting directory.
find_manifest_with_optional
Find the manifest file, using an explicit path if provided.