Primitive Types
This document describes the enhanced primitive discovery system implemented for APM CLI, providing dependency support with source tracking and conflict detection.
Overview
Section titled “Overview”The enhanced primitive discovery system extends the existing primitive discovery functionality to support:
- Dependency-aware discovery: Scan primitives from both local
.apm/directories and dependency packages inapm_modules/ - Source tracking: Every primitive knows where it came from (
localordependency:{package_name}) - Priority system: Local primitives always override dependency primitives; dependencies processed in declaration order
- Conflict detection: Track when multiple sources provide the same primitive and report which source wins
Key Features
Section titled “Key Features”1. Source Tracking
Section titled “1. Source Tracking”All primitive models (Chatmode, Instruction, Context) now include an optional source field:
from apm_cli.primitives import Chatmode
# Local primitivechatmode = Chatmode( name="assistant", file_path=Path("local.chatmode.md"), description="Local assistant", content="...", source="local" # New field)
# Dependency primitivedep_chatmode = Chatmode( name="reviewer", file_path=Path("dep.chatmode.md"), description="Dependency assistant", content="...", source="dependency:company-standards" # New field)2. Enhanced Discovery Functions
Section titled “2. Enhanced Discovery Functions”discover_primitives_with_dependencies(base_dir=".")
Section titled “discover_primitives_with_dependencies(base_dir=".")”Main enhanced discovery function that:
- Scans local
.apm/directory (highest priority) - Scans dependency packages in
apm_modules/(lower priority, in declaration order) - Applies conflict resolution (local always wins)
- Returns
PrimitiveCollectionwith source tracking and conflict information
discover_primitives(base_dir=".")
Section titled “discover_primitives(base_dir=".")”Original discovery function - unchanged for backward compatibility. Only scans local primitives.
3. Conflict Detection
Section titled “3. Conflict Detection”The PrimitiveCollection class now tracks conflicts when multiple sources provide primitives with the same name:
collection = discover_primitives_with_dependencies()
# Check for conflictsif collection.has_conflicts(): for conflict in collection.conflicts: print(f"Conflict: {conflict}") # Output: "chatmode 'assistant': local overrides dependency:company-standards"4. Priority System
Section titled “4. Priority System”- Local primitives always win: Primitives in local
.apm/directory override any dependency primitives with the same name - Dependency order matters: Dependencies are processed in the order declared in
apm.yml; first declared dependency wins conflicts with later dependencies
5. Source-based Filtering
Section titled “5. Source-based Filtering”collection = discover_primitives_with_dependencies()
# Get primitives by sourcelocal_primitives = collection.get_primitives_by_source("local")dep_primitives = collection.get_primitives_by_source("dependency:package-name")
# Get conflicts by typechatmode_conflicts = collection.get_conflicts_by_type("chatmode")Usage Examples
Section titled “Usage Examples”Basic Enhanced Discovery
Section titled “Basic Enhanced Discovery”from apm_cli.primitives import discover_primitives_with_dependencies
# Discover all primitives (local + dependencies)collection = discover_primitives_with_dependencies("/path/to/project")
print(f"Total primitives: {collection.count()}")print(f"Conflicts detected: {collection.has_conflicts()}")
for primitive in collection.all_primitives(): print(f"- {primitive.name} from {primitive.source}")Handling Conflicts
Section titled “Handling Conflicts”collection = discover_primitives_with_dependencies()
if collection.has_conflicts(): print("Conflicts detected:") for conflict in collection.conflicts: print(f" - {conflict.primitive_name}: {conflict.winning_source} wins") print(f" Overrides: {', '.join(conflict.losing_sources)}")Dependency Declaration Order
Section titled “Dependency Declaration Order”The system reads apm.yml to determine the order in which direct dependencies should be processed. Transitive dependencies (resolved automatically via dependency chains) are read from apm.lock and appended after direct dependencies:
name: my-projectversion: 1.0.0dependencies: apm: - company/standards#v1.0.0 - team/workflows@workflow-alias - user/utilitiesDirect dependencies are processed first, in declaration order. Transitive dependencies from apm.lock are appended after. If multiple dependencies provide primitives with the same name, the first one declared wins.
Directory Structure
Section titled “Directory Structure”The enhanced discovery system expects this structure:
project/├── apm.yml # Dependency declarations├── .apm/ # Local primitives (highest priority)│ ├── chatmodes/│ ├── instructions/│ └── contexts/└── apm_modules/ # Dependency primitives ├── standards/ # From company/standards │ └── .apm/ │ ├── chatmodes/ │ └── instructions/ ├── workflow-alias/ # From team/workflows (uses alias) │ └── .apm/ │ └── contexts/ └── utilities/ # From user/utilities └── .apm/ └── instructions/Backward Compatibility
Section titled “Backward Compatibility”All changes are fully backward compatible:
- Existing
discover_primitives()function unchanged - Existing primitive constructors work unchanged (source field is optional)
- Existing
PrimitiveCollectionmethods work unchanged - All existing tests continue to pass
Integration Points
Section titled “Integration Points”The enhanced discovery system integrates with:
- APM Package Models: Uses
APMPackageandDependencyReferencefrom Task 1 to parseapm.yml - Existing Parser: Extends existing primitive parser with optional source parameter
- Future Compilation: Prepared for integration with compilation system for source attribution
Technical Details
Section titled “Technical Details”Conflict Resolution Algorithm
Section titled “Conflict Resolution Algorithm”- Create empty
PrimitiveCollection - Scan local
.apm/directory, add all primitives withsource="local" - Parse
apm.ymlto get dependency declaration order - For each dependency in order:
- Scan
apm_modules/{dependency}/.apm/directory - Add primitives with
source="dependency:{dependency}" - If primitive name conflicts with existing primitive:
- Keep existing primitive (higher priority)
- Record conflict with losing source information
- Scan
Conflict detection uses O(1) name-indexed lookups, so performance remains constant regardless of collection size.
Error Handling
Section titled “Error Handling”- Gracefully handles missing
apm_modules/directory - Gracefully handles missing
apm.ymlfile - Gracefully handles invalid dependency directories
- Continues processing other dependencies if one fails
- Reports warnings for unparseable primitive files
Testing
Section titled “Testing”Comprehensive test suite in tests/test_enhanced_discovery.py covers:
- Source tracking functionality
- Conflict detection accuracy
- Priority system validation
- Dependency order parsing
- Backward compatibility
- Edge cases and error conditions
Run tests with:
python -m pytest tests/test_enhanced_discovery.py -vFuture Enhancements
Section titled “Future Enhancements”The enhanced discovery system is designed to support future features:
- Compilation Integration: Source attribution in generated
AGENTS.mdfiles - CLI Commands:
apm deps list,apm compile --tracecommands - Advanced Conflict Resolution: User-configurable conflict resolution strategies
- Performance Optimization: Caching and incremental discovery for large projects