Skip to content
NeuroCognitive Architecture Badge

NeuroCognitive Architecture (NCA) - Architecture Decisions

Package Structure

Src-Layout Pattern

We've implemented the recommended src-layout pattern for Python packages, which provides several important benefits:

  1. Clean Separation:
  2. Source code is isolated in the src/neuroca directory
  3. Tests reside outside the package in a dedicated tests directory
  4. Configuration files remain at the project root

  5. Import Clarity:

  6. Eliminates confusion between local imports and installed package imports
  7. Forces explicit imports that work correctly in all contexts
  8. Prevents common pitfalls with relative imports

  9. Test Reliability:

  10. Tests run against the installed package rather than source files
  11. Ensures tests reflect real-world usage patterns
  12. Eliminates hidden dependencies or path manipulation hacks

  13. Deployment Consistency:

  14. Package behaves the same in development and production
  15. Built package includes only necessary files
  16. Clear boundary between package code and project tooling

The implementation follows Python packaging best practices, with this structure:

project_root/
├── src/
│   └── neuroca/            # Main package
│       ├── __init__.py     # Package initialization
│       ├── core/           # Core components
│       │   ├── __init__.py
│       │   ├── health/     # Health monitoring system
│       │   └── memory/     # Memory systems
│       ├── api/            # API endpoints and schemas
│       ├── cli/            # Command-line interface
│       ├── db/             # Database connections and models
│       └── ...             # Other modules
├── tests/                  # Test directory (outside package)
├── pyproject.toml          # Project configuration
└── ...                     # Other project files

This aligns with the recommendations from: - pytest documentation on good practices - Python Packaging Authority (PyPA) - Ionel Cristian Mărieș' blog posts on Python packaging

Namespace Structure

Our package namespace follows a hierarchical structure:

  1. Core Cognitive Components:
  2. neuroca.core.memory: Memory systems implementations
  3. neuroca.core.health: Health monitoring and regulation
  4. neuroca.core.cognition: Higher-level cognitive processes

  5. Infrastructure Components:

  6. neuroca.api: API endpoints and schemas
  7. neuroca.cli: Command-line interfaces
  8. neuroca.db: Database connections and models
  9. neuroca.monitoring: Logging, metrics, and tracing

  10. Integration Components:

  11. neuroca.integration: External system integrations
  12. neuroca.utils: Shared utilities
  13. neuroca.models: Data models and schemas

Design Patterns

Interface-Based Design

To break circular dependencies and enable more modular development, we've implemented an interface-based design approach:

  1. Abstract Base Classes:
  2. Define contracts through abstract methods and properties
  3. Establish clear boundaries between components
  4. Provide type safety through explicit interfaces

  5. Dependency Inversion:

  6. Components depend on abstractions rather than concrete implementations
  7. High-level modules are decoupled from low-level modules
  8. Makes the system more testable and maintainable

Key interfaces in the memory system:

class MemoryChunk(Generic[T], ABC):
    """Represents a single unit of memory content with activation level."""

    @property
    @abstractmethod
    def id(self) -> str:
        """Get the unique identifier for this memory chunk."""
        pass

    @property
    @abstractmethod
    def content(self) -> T:
        """Get the content of this memory chunk."""
        pass

    # Additional properties and methods...

class MemorySystem(ABC):
    """Abstract base class for all memory systems."""

    @property
    @abstractmethod
    def name(self) -> str:
        """Get the name of this memory system."""
        pass

    @abstractmethod
    def store(self, content: Any, **metadata) -> str:
        """Store content in this memory system."""
        pass

    # Additional methods...

Factory Pattern

We've implemented the Factory pattern for memory systems to:

  1. Decouple Creation from Use:
  2. Clients use a simple factory function to create memory systems
  3. Creation logic is centralized in one location
  4. Implementation details are hidden from clients

  5. Enable Runtime Registration:

  6. Memory system implementations register themselves with the factory
  7. New systems can be added without modifying factory code
  8. Simplifies dependency management

Implementation:

# Registry of available memory systems
_memory_system_registry: Dict[str, Type[MemorySystem]] = {}

def register_memory_system(name: str, cls: Type[MemorySystem]) -> None:
    """Register a memory system implementation."""
    _memory_system_registry[name] = cls

def create_memory_system(memory_type: str, **config) -> MemorySystem:
    """Create a memory system of the specified type."""
    # Normalize name and create instance
    memory_type = memory_type.lower()
    memory_type = _memory_type_aliases.get(memory_type, memory_type)

    if memory_type not in _memory_system_registry:
        raise ValueError(f"Unknown memory system type: {memory_type}")

    return _memory_system_registry[memory_type](**config)

Biological Fidelity Patterns

Our architecture incorporates patterns inspired by biological cognition:

  1. Tiered Memory System:
  2. Working Memory: Limited capacity (7±2 chunks), high activation
  3. Episodic Memory: Experiences with temporal and emotional context
  4. Semantic Memory: Abstract knowledge in a graph structure

  5. Decay Mechanisms:

  6. Time-based decay for working memory
  7. Interference-based forgetting
  8. Emotional salience affecting retention

  9. Health Dynamics:

  10. Resource monitoring (energy, attention)
  11. Homeostatic regulation
  12. Adaptive responses based on system state

Technology Stack Decisions

Core Framework

We've chosen FastAPI for our API implementation because:

  1. Performance:
  2. Async capability matches our concurrent processing needs
  3. Minimal overhead compared to alternatives

  4. Type Safety:

  5. Pydantic integration for runtime type validation
  6. Automatic schema generation for API documentation

  7. Developer Experience:

  8. Intuitive API for defining endpoints
  9. Excellent documentation and community support

Dependency Management

We've chosen Poetry for dependency management because:

  1. Reproducibility:
  2. Exact dependency locking via poetry.lock
  3. Consistent environment across development and deployment

  4. Modern Workflow:

  5. Combined dependency and package management
  6. Virtual environment handling built-in

  7. Publishing Support:

  8. Simple publication to PyPI
  9. Metadata management in a single location (pyproject.toml)

Storage Strategy

Our storage architecture employs multiple specialized systems:

  1. Working Memory:
  2. In-memory with Redis for distributed scenarios
  3. Optimized for fast access and real-time operations

  4. Episodic Memory:

  5. PostgreSQL with vector extension for similarity search
  6. JSONB for flexible schema evolution

  7. Semantic Memory:

  8. Neo4j graph database for relationship traversal
  9. Property graph model for typed relationships

Implementation Approach

Test-Driven Development

We follow a strict TDD approach for all core components:

  1. Test First:
  2. Write tests based on interface specifications
  3. Define biological constraints in test assertions
  4. Implement only what's needed to make tests pass

  5. Test Coverage:

  6. Target >95% coverage for core cognitive components
  7. Include boundary conditions and error cases
  8. Test biologically-inspired behaviors explicitly

Continuous Validation

Our development process includes continuous checks for:

  1. Biological Plausibility:
  2. Verify capacity constraints
  3. Test emotional effects on memory
  4. Validate decay curves against cognitive models

  5. Performance Metrics:

  6. Memory retrieval latency
  7. Scaling under increasing cognitive load
  8. Resource consumption during operation

Incremental Implementation

We're following a phase-based implementation approach:

  1. Phase 1: Package restructuring and interface definitions
  2. Phase 2: Core memory system implementations
  3. Phase 3: Health dynamics and cognitive processes
  4. Phase 4: LLM integration and optimization
  5. Phase 5: Production deployment and monitoring