# MLX Hybrid Embedding Backend Implementation Plan
# Option D: Ollama fallback + MLX with feature flag
#
# PRODUCERS: Task 1 → EmbeddingProvider Protocol, Task 2 → EmbeddingBackend Enum
# PRODUCERS: Task 3 → OllamaProvider, Task 4 → MLXProvider
# PRODUCERS: Task 5 → create_embedding_provider factory
# CONSUMERS: Task 6 → [1, 2, 5], Task 7 → [1, 2, 5], Task 8 → [3, 4, 5]
# VALIDATION: All consumers depend_on producers ✓
conductor:
default_agent: python-pro
worktree_groups:
- group_id: "foundation"
tasks: [1, 2]
rationale: "Protocol and config must exist before providers"
- group_id: "ollama-provider"
tasks: [3]
rationale: "OllamaProvider refactor (modifies __init__.py)"
- group_id: "mlx-provider"
tasks: [4]
rationale: "MLXProvider creation (also modifies __init__.py, depends on 3)"
- group_id: "integration"
tasks: [5, 6, 7]
rationale: "Factory and integration depend on providers"
- group_id: "testing"
tasks: [8, 9]
rationale: "End-to-end testing after integration complete"
planner_compliance:
planner_version: "4.0.0"
strict_enforcement: true
required_features: [dependency_checks, test_commands, success_criteria, data_flow_registry]
data_flow_registry:
producers:
EmbeddingProvider:
- task: 1
description: "Creates Protocol/ABC defining embed() and embed_batch() interface"
EmbeddingBackend:
- task: 2
description: "Creates Literal type for backend selection (ollama, mlx)"
OllamaProvider:
- task: 3
description: "Refactors OllamaClient to implement EmbeddingProvider"
MLXProvider:
- task: 4
description: "Creates new MLX-based provider with async wrapper"
create_embedding_provider:
- task: 5
description: "Factory function to instantiate correct provider based on config"
consumers:
EmbeddingProvider:
- task: 3
description: "OllamaProvider implements this protocol"
- task: 4
description: "MLXProvider implements this protocol"
- task: 6
description: "HybridStore uses protocol for type hints"
- task: 7
description: "Daemon uses protocol for type hints"
EmbeddingBackend:
- task: 5
description: "Factory uses enum to select provider"
- task: 6
description: "HybridStore.create() accepts backend parameter"
create_embedding_provider:
- task: 6
description: "HybridStore.create() calls factory"
- task: 7
description: "Daemon calls factory"
plan:
metadata:
feature_name: "MLX Hybrid Embedding Backend"
created: "2026-01-14"
target: "Add MLX embedding backend with Ollama fallback via feature flag"
rationale: "10x latency improvement (50-200ms → 5-7ms) on Apple Silicon"
context:
framework: "Python 3.11+"
test_framework: "pytest"
key_dependencies:
- "mlx-embeddings>=0.0.3"
- "pydantic>=2.0"
- "httpx>=0.24"
tasks:
# ============================================
# TASK 1: EmbeddingProvider Protocol
# ============================================
- task_number: "1"
name: "Create EmbeddingProvider Protocol"
agent: "python-pro"
files:
- "src/recall/embedding/provider.py"
depends_on: []
success_criteria:
- "EmbeddingProvider Protocol defines async embed(text, is_query) -> List[float]"
- "EmbeddingProvider Protocol defines async embed_batch(texts, is_query, batch_size) -> List[List[float]]"
- "EmbeddingProvider Protocol defines async close() for cleanup"
- "EmbeddingProvider supports async context manager (__aenter__, __aexit__)"
- "EmbeddingError exception class exported from module"
- "No TODO comments in production code"
- "No placeholder structs"
- "All imports resolve"
test_commands:
- "cd /Users/harrison/Documents/Github/recall && uv run pytest tests/unit/test_embedding_provider.py -v"
- "cd /Users/harrison/Documents/Github/recall && uv run python -c 'from recall.embedding.provider import EmbeddingProvider, EmbeddingError'"
runtime_metadata:
dependency_checks:
- command: "cd /Users/harrison/Documents/Github/recall && uv run python -c 'from typing import Protocol, runtime_checkable'"
description: "Verify typing imports available"
documentation_targets: []
description: |
<dependency_verification priority="execute_first">
<commands>
cd /Users/harrison/Documents/Github/recall && uv run python -c "from typing import Protocol"
</commands>
</dependency_verification>
<task_description>
Create the EmbeddingProvider Protocol that defines the interface for all embedding backends.
This protocol uses @runtime_checkable to enable isinstance() checks.
The interface mirrors OllamaClient's public methods: embed(), embed_batch(), close().
Include EmbeddingError exception for provider-specific errors.
</task_description>
implementation:
approach: |
Create a new module src/recall/embedding/provider.py that defines:
1. @runtime_checkable Protocol class EmbeddingProvider
2. Abstract methods matching OllamaClient interface
3. EmbeddingError exception (move from ollama.py or re-export)
key_points:
- point: "EmbeddingProvider Protocol with @runtime_checkable"
details: "Allows isinstance() checks at runtime for duck typing validation"
reference: "src/recall/embedding/provider.py"
- point: "Async method signatures matching OllamaClient"
details: "embed(text: str, is_query: bool = False) -> List[float]"
reference: "src/recall/embedding/ollama.py:177-219"
- point: "Async context manager support"
details: "__aenter__ returns self, __aexit__ calls close()"
reference: "src/recall/embedding/ollama.py:77-83"
code_quality:
python:
full_quality_pipeline:
command: "cd /Users/harrison/Documents/Github/recall && uv run ruff check src/recall/embedding/provider.py && uv run ruff format src/recall/embedding/provider.py"
exit_on_failure: true
commit:
type: "feat"
message: "add EmbeddingProvider protocol for backend abstraction"
files:
- "src/recall/embedding/provider.py"
- "tests/unit/test_embedding_provider.py"
status: "completed"
execution_history:
- attempt_number: "1"
commit_verification:
found: true
hash: e9968a8
message: 'feat: add EmbeddingProvider protocol for backend abstraction'
- attempt_number: "1"
agent: python-pro
verdict: GREEN
agent_output: '{"errors":[],"files_modified":["src/recall/embedding/provider.py","tests/unit/test_embedding_provider.py"],"metadata":{"commit_hash":"e9968a8","tests_failed":0,"tests_passed":12},"output":"Created src/recall/embedding/provider.py with:\n- @runtime_checkable EmbeddingProvider Protocol class\n- Method signatures matching OllamaClient: embed(), embed_batch(), close()\n- Async context manager support: __aenter__, __aexit__\n- Re-exported EmbeddingError from ollama.py for convenience\n\nCreated tests/unit/test_embedding_provider.py with 12 tests:\n- Protocol is runtime_checkable (isinstance works)\n- OllamaClient conforms to the Protocol\n- Conforming classes are recognized as providers\n- Non-conforming classes (missing methods) are rejected\n- EmbeddingError export verification\n- Method signature validation\n\nAll 12 tests pass.\n\nArchitectural decisions:\n1. Protocol Pattern: @runtime_checkable enables structural typing with runtime verification\n2. EmbeddingError: Re-exported from ollama.py to avoid breaking imports\n3. Interface: Mirrors OllamaClient exactly for backward compatibility\n4. is_query parameter: Retained for mxbai-specific query prefixes; providers can ignore if not applicable","status":"success","summary":"Created EmbeddingProvider Protocol with @runtime_checkable for embedding backend abstraction"}'
qc_feedback: |-
[code-reviewer] The EmbeddingProvider Protocol implementation is complete and well-designed. The agent created the exact required file (src/recall/embedding/provider.py) with a @runtime_checkable Protocol that defines the complete async interface (embed, embed_batch, close) plus async context manager support (__aenter__, __aexit__). EmbeddingError is properly re-exported from ollama.py. All 12 tests pass, verifying Protocol conformance, OllamaClient compatibility, and method signatures. The commit was created as requested.
[python-schema-architect] The implementation successfully creates the EmbeddingProvider Protocol with all required functionality. The Protocol is properly decorated with @runtime_checkable, includes all three required async methods (embed, embed_batch, close) with correct signatures, implements async context manager support (__aenter__, __aexit__), and re-exports EmbeddingError from the ollama module. All 12 tests pass, validating runtime type checking, OllamaClient conformance, and method signatures. No TODO comments or placeholders exist in the production code. The architectural decision to re-export EmbeddingError (rather than creating a new exception) maintains backward compatibility with existing code.
[architect-reviewer] Task successfully completed. The EmbeddingProvider Protocol was created correctly at src/recall/embedding/provider.py with all required methods and features. The implementation includes @runtime_checkable decorator for isinstance() checks, async methods (embed, embed_batch, close), async context manager support (__aenter__, __aexit__), and re-exports EmbeddingError from the ollama module. All 12 unit tests pass, verifying Protocol conformance detection and method signatures. The commit was made with the correct message (e9968a8).
[fastapi-pro] The implementation successfully creates a well-designed EmbeddingProvider Protocol with all required functionality. The Protocol is @runtime_checkable, defines all required async methods (embed, embed_batch, close), supports async context manager pattern (__aenter__, __aexit__), and re-exports EmbeddingError from the ollama module for convenience. All 12 tests pass, verifying that OllamaClient conforms to the Protocol and that non-conforming classes are correctly rejected.
timestamp: "2026-01-14T11:28:13Z"
completed_date: "2026-01-14"
# ============================================
# TASK 2: Add EmbeddingBackend Config
# ============================================
- task_number: "2"
name: "Add EmbeddingBackend configuration option"
agent: "python-pro"
files:
- "src/recall/config.py"
depends_on: []
success_criteria:
- "EmbeddingBackend Literal type defines 'ollama' and 'mlx' options"
- "RecallSettings.embedding_backend field with default='ollama'"
- "RECALL_EMBEDDING_BACKEND environment variable override works"
- "RecallSettings.mlx_model field for MLX-specific model path"
- "No TODO comments in production code"
- "All imports resolve"
test_commands:
- "cd /Users/harrison/Documents/Github/recall && uv run pytest tests/unit/test_config.py -v -k embedding"
- "cd /Users/harrison/Documents/Github/recall && RECALL_EMBEDDING_BACKEND=mlx uv run python -c 'from recall.config import RecallSettings; s = RecallSettings(); assert s.embedding_backend == \"mlx\"'"
runtime_metadata:
dependency_checks:
- command: "cd /Users/harrison/Documents/Github/recall && uv run python -c 'from recall.config import RecallSettings'"
description: "Verify config module loads"
documentation_targets: []
description: |
<dependency_verification priority="execute_first">
<commands>
cd /Users/harrison/Documents/Github/recall && uv run python -c "from recall.config import RecallSettings"
</commands>
</dependency_verification>
<task_description>
Add embedding_backend configuration field to RecallSettings.
This field controls which embedding provider is used (ollama or mlx).
Default is 'ollama' for backward compatibility.
Also add mlx_model field for specifying the MLX model to use.
</task_description>
implementation:
approach: |
Modify src/recall/config.py to add:
1. EmbeddingBackend Literal type ('ollama' | 'mlx')
2. embedding_backend field in RecallSettings with default='ollama'
3. mlx_model field for MLX model path (default: mlx-community/mxbai-embed-large-v1)
key_points:
- point: "EmbeddingBackend Literal type"
details: "Literal['ollama', 'mlx'] for type-safe backend selection"
reference: "src/recall/config.py:15"
- point: "embedding_backend field with default='ollama'"
details: "Backward compatible - existing deployments continue using Ollama"
reference: "src/recall/config.py:63-75"
- point: "mlx_model field for MLX model specification"
details: "Default to mlx-community/mxbai-embed-large-v1 for compatibility"
reference: "src/recall/config.py"
code_quality:
python:
full_quality_pipeline:
command: "cd /Users/harrison/Documents/Github/recall && uv run ruff check src/recall/config.py && uv run ruff format src/recall/config.py"
exit_on_failure: true
commit:
type: "feat"
message: "add embedding_backend config option (ollama/mlx)"
files:
- "src/recall/config.py"
- "tests/unit/test_config.py"
status: "completed"
execution_history:
- attempt_number: "1"
commit_verification:
found: true
hash: c8385c2
message: 'feat: add embedding_backend config option (ollama/mlx)'
- attempt_number: "1"
agent: python-pro
verdict: GREEN
agent_output: '{"errors":[],"files_modified":["src/recall/config.py","tests/unit/test_config.py"],"metadata":{"branch":"feature/hybrid_mlx_embeddings","commit":"c8385c2","tests_passed":16},"output":"Added embedding_backend configuration to RecallSettings:\n\n1. **EmbeddingBackend type alias**: `Literal[\"ollama\", \"mlx\"]` for type-safe backend selection\n2. **embedding_backend field**: Default ''ollama'' for backward compatibility, configurable via RECALL_EMBEDDING_BACKEND env var\n3. **mlx_model field**: Default ''mlx-community/mxbai-embed-large-v1'', configurable via RECALL_MLX_MODEL env var\n4. **Updated docstring**: Documented new attributes\n5. **Unit tests**: 7 tests covering defaults, env var overrides, validation errors, and type alias verification\n\nArchitectural justification:\n- Literal type provides compile-time and runtime validation for backend values\n- Default ''ollama'' maintains backward compatibility with existing deployments\n- Pattern follows existing Field() conventions in RecallSettings\n- Pydantic validation automatically rejects invalid backend values with clear error messages","status":"success","summary":"Added EmbeddingBackend configuration option to RecallSettings with ''ollama'' (default) and ''mlx'' backends, plus mlx_model field for MLX model specification."}'
qc_feedback: |-
[code-reviewer] Agent code-reviewer failed: validation failed despite schema: verdict is required
[python-schema-architect] All success criteria are satisfied. The implementation correctly adds the EmbeddingBackend configuration option to RecallSettings with proper Literal type definition, default values for backward compatibility, and comprehensive test coverage. The commit c8385c2 contains the expected changes to src/recall/config.py and tests/unit/test_config.py. Both test commands passed successfully.
[architect-reviewer] Agent architect-reviewer failed: validation failed despite schema: verdict is required
[test-automator] Implementation successfully adds EmbeddingBackend configuration to RecallSettings. The type alias EmbeddingBackend = Literal["ollama", "mlx"] provides type-safe backend selection. The embedding_backend field defaults to 'ollama' for backward compatibility, and the mlx_model field defaults to 'mlx-community/mxbai-embed-large-v1'. All tests pass including environment variable override verification. No TODO comments found in production code. Architectural decision justified: Literal type follows Pydantic patterns already in use and provides both compile-time and runtime validation for constrained string values.
timestamp: "2026-01-14T11:36:56Z"
completed_date: "2026-01-14"
# ============================================
# TASK 3: Refactor OllamaClient to OllamaProvider
# ============================================
- task_number: "3"
name: "Refactor OllamaClient to implement EmbeddingProvider"
agent: "python-pro"
files:
- "src/recall/embedding/ollama.py"
- "src/recall/embedding/__init__.py"
depends_on: [1]
success_criteria:
- "OllamaClient class implements EmbeddingProvider protocol"
- "OllamaProvider alias exported for consistency with new naming"
- "Existing OllamaClient API unchanged for backward compatibility"
- "EmbeddingProvider imported in ollama.py module"
- "All existing tests pass without modification"
- "No TODO comments in production code"
- "All imports resolve"
test_commands:
- "cd /Users/harrison/Documents/Github/recall && uv run pytest tests/unit/test_ollama_client.py -v"
- "cd /Users/harrison/Documents/Github/recall && uv run python -c 'from recall.embedding.ollama import OllamaClient, OllamaProvider; from recall.embedding.provider import EmbeddingProvider; assert isinstance(OllamaClient(\"http://localhost:11434\", \"test\"), EmbeddingProvider)'"
runtime_metadata:
dependency_checks:
- command: "cd /Users/harrison/Documents/Github/recall && uv run python -c 'from recall.embedding.provider import EmbeddingProvider'"
description: "Verify EmbeddingProvider protocol exists (Task 1)"
documentation_targets: []
description: |
<dependency_verification priority="execute_first">
<commands>
cd /Users/harrison/Documents/Github/recall && uv run python -c "from recall.embedding.provider import EmbeddingProvider"
</commands>
</dependency_verification>
<task_description>
Refactor OllamaClient to explicitly implement the EmbeddingProvider protocol.
This is mostly a documentation change since OllamaClient already has the correct interface.
Add OllamaProvider as an alias for naming consistency with MLXProvider.
Update __init__.py to export both names.
</task_description>
implementation:
approach: |
1. Import EmbeddingProvider in ollama.py
2. Add type annotation showing OllamaClient implements protocol
3. Create OllamaProvider = OllamaClient alias
4. Update __init__.py exports
key_points:
- point: "OllamaClient implements EmbeddingProvider"
details: "Add explicit Protocol inheritance documentation"
reference: "src/recall/embedding/ollama.py:28"
- point: "OllamaProvider alias for naming consistency"
details: "OllamaProvider = OllamaClient at module level"
reference: "src/recall/embedding/ollama.py"
- point: "Backward compatible - no API changes"
details: "Existing code using OllamaClient continues to work"
reference: "src/recall/embedding/ollama.py"
code_quality:
python:
full_quality_pipeline:
command: "cd /Users/harrison/Documents/Github/recall && uv run ruff check src/recall/embedding/ && uv run ruff format src/recall/embedding/"
exit_on_failure: true
commit:
type: "refactor"
message: "OllamaClient implements EmbeddingProvider protocol"
files:
- "src/recall/embedding/ollama.py"
- "src/recall/embedding/__init__.py"
status: "completed"
execution_history:
- attempt_number: "1"
commit_verification:
found: true
hash: 6b19c3e
message: 'refactor: OllamaClient implements EmbeddingProvider protocol'
- attempt_number: "1"
agent: python-pro
verdict: RED
agent_output: '{"errors":[],"files_modified":["src/recall/embedding/ollama.py","src/recall/embedding/__init__.py"],"output":"Successfully completed the refactor:\n\n1. Updated ollama.py:\n - Added docstring note about implementing EmbeddingProvider protocol\n - Updated OllamaClient class docstring to reference protocol compliance\n - Added OllamaProvider = OllamaClient alias for naming consistency with MLXProvider\n\n2. Updated __init__.py:\n - Added import for OllamaProvider alias\n - Added import for EmbeddingProvider from provider module\n - Updated __all__ to export EmbeddingProvider, OllamaClient, OllamaProvider, EmbeddingError, EMBED_PREFIX\n\nVerification:\n- OllamaProvider is OllamaClient: True\n- isinstance(OllamaClient(), EmbeddingProvider): True\n- All 535 tests pass\n\nCommit: 6b19c3e \"refactor: OllamaClient implements EmbeddingProvider protocol\"","status":"success","summary":"Refactored OllamaClient to document EmbeddingProvider protocol implementation and added OllamaProvider alias"}'
qc_feedback: |-
[code-reviewer] All success criteria satisfied. The OllamaClient correctly implements the EmbeddingProvider protocol through structural typing, the OllamaProvider alias is exported for naming consistency, backward compatibility is maintained, imports resolve correctly, tests pass, and there are no TODO comments in production code.
[python-pro] Successfully refactored OllamaClient to implement EmbeddingProvider protocol. The implementation correctly documents protocol compliance in docstrings, adds the OllamaProvider alias for naming consistency, exports all required symbols from __init__.py, and maintains full backward compatibility. All 21 tests pass, and the isinstance check verifies protocol compliance at runtime.
[refactoring-specialist] Implementation is functionally correct and all tests pass, but criterion 4 "EmbeddingProvider imported in ollama.py module" is not satisfied. The ollama.py file references EmbeddingProvider in docstrings only but does not contain an actual import statement. This is likely intentional to avoid circular imports (provider.py imports EmbeddingError from ollama.py), but the explicit criterion requires the import. The structural typing works regardless - isinstance() checks pass because OllamaClient has all required methods. The agent should add a comment explaining why the import is omitted (circular import avoidance) or use TYPE_CHECKING to import for type annotation purposes only.
[architect-reviewer] The refactoring task has been completed correctly. OllamaClient now documents its implementation of the EmbeddingProvider protocol (line 34-35 of ollama.py), OllamaProvider alias is exported (line 290), and __init__.py properly exports all required symbols including EmbeddingProvider, OllamaClient, and OllamaProvider. All 21 tests pass and the isinstance() check confirms protocol compliance. The commit was created with the correct message.
timestamp: "2026-01-14T11:43:18Z"
- attempt_number: "2"
commit_verification:
found: true
hash: 1a26cbb
message: 'refactor: OllamaClient implements EmbeddingProvider protocol'
- attempt_number: "2"
agent: python-integration-specialist
verdict: GREEN
agent_output: '{"errors":[],"files_modified":["src/recall/embedding/ollama.py"],"output":"Changes made to src/recall/embedding/ollama.py:\n1. Added `from __future__ import annotations` for forward reference support\n2. Added TYPE_CHECKING import from typing\n3. Added conditional import: `from recall.embedding.provider import EmbeddingProvider` inside TYPE_CHECKING block\n4. This avoids circular imports (provider.py imports EmbeddingError from ollama.py) while satisfying the explicit import requirement\n\nVerification:\n- All 535 tests pass\n- isinstance(OllamaClient(), EmbeddingProvider) returns True\n- isinstance(OllamaProvider(), EmbeddingProvider) returns True\n- All exports from __init__.py work correctly\n- EmbeddingProvider import now appears on line 21 of ollama.py\n\nCommit: 1a26cbb - \"refactor: OllamaClient implements EmbeddingProvider protocol\"","status":"success","summary":"Refactored OllamaClient to explicitly import EmbeddingProvider using TYPE_CHECKING to avoid circular imports while satisfying the criterion that EmbeddingProvider must be imported in ollama.py."}'
qc_feedback: |-
[code-reviewer] All success criteria are satisfied. OllamaClient correctly implements the EmbeddingProvider protocol through structural typing with the import present in ollama.py via TYPE_CHECKING block (line 20-21). The OllamaProvider alias is exported (line 295), backward compatibility is maintained, all 21 tests pass, no TODO comments exist, and all imports resolve correctly. The agent properly addressed the previous QC feedback by adding the EmbeddingProvider import using TYPE_CHECKING to avoid circular imports.
[python-pro] All success criteria have been satisfied. The OllamaClient correctly implements the EmbeddingProvider protocol through structural typing with an explicit TYPE_CHECKING import on line 20-21 of ollama.py. The OllamaProvider alias is exported on line 295. The __init__.py exports all required symbols (EmbeddingProvider, OllamaClient, OllamaProvider). All 21 tests pass, isinstance() verification confirms protocol compliance, no TODO comments exist in production code, and all imports resolve correctly. The TYPE_CHECKING import pattern correctly avoids the circular import issue between provider.py and ollama.py while satisfying criterion 3.
[refactoring-specialist] All success criteria satisfied. OllamaClient correctly implements the EmbeddingProvider protocol through structural typing, with EmbeddingProvider imported in ollama.py using TYPE_CHECKING to avoid circular imports (line 20-21). The OllamaProvider alias is exported (line 295), backward compatibility is maintained (existing API unchanged), all imports resolve correctly, all 21 tests pass, and no TODO comments exist in production code.
[architect-reviewer] All success criteria satisfied. OllamaClient correctly implements the EmbeddingProvider protocol through structural typing. The EmbeddingProvider import is now present in ollama.py at line 21 using TYPE_CHECKING to avoid circular imports (since provider.py imports EmbeddingError from ollama.py). The OllamaProvider alias is exported for naming consistency, backward compatibility is maintained, all 21 tests pass, no TODO comments exist in production code, and all imports resolve correctly. The commit was created with the correct message.
timestamp: "2026-01-14T11:45:44Z"
completed_date: "2026-01-14"
# ============================================
# TASK 4: Create MLXProvider
# ============================================
- task_number: "4"
name: "Create MLXProvider embedding backend"
agent: "python-pro"
files:
- "src/recall/embedding/mlx_provider.py"
- "src/recall/embedding/__init__.py"
depends_on: [1, 3] # Depends on 3 to avoid __init__.py conflict
success_criteria:
- "MLXProvider class implements EmbeddingProvider protocol"
- "MLXProvider uses mlx-embeddings library for embedding generation"
- "MLXProvider wraps sync mlx-embeddings calls with asyncio.to_thread()"
- "MLXProvider.__init__ accepts model parameter (default: mlx-community/mxbai-embed-large-v1)"
- "MLXProvider.embed() applies query prefix for mxbai models when is_query=True"
- "MLXProvider.embed_batch() processes texts with configurable batch_size"
- "MLXProvider gracefully handles ImportError if mlx-embeddings not installed"
- "MLXProvider exported from embedding/__init__.py"
- "No TODO comments in production code"
- "All imports resolve"
test_commands:
- "cd /Users/harrison/Documents/Github/recall && uv run pytest tests/unit/test_mlx_provider.py -v"
- "cd /Users/harrison/Documents/Github/recall && uv run python -c 'from recall.embedding.mlx_provider import MLXProvider'"
runtime_metadata:
dependency_checks:
- command: "cd /Users/harrison/Documents/Github/recall && uv run python -c 'from recall.embedding.provider import EmbeddingProvider'"
description: "Verify EmbeddingProvider protocol exists (Task 1)"
- command: "cd /Users/harrison/Documents/Github/recall && uv run pip show mlx-embeddings || echo 'mlx-embeddings not installed - will be optional'"
description: "Check if mlx-embeddings available"
documentation_targets: []
description: |
<dependency_verification priority="execute_first">
<commands>
cd /Users/harrison/Documents/Github/recall && uv run python -c "from recall.embedding.provider import EmbeddingProvider"
</commands>
</dependency_verification>
<task_description>
Create MLXProvider class that implements EmbeddingProvider using mlx-embeddings.
Since mlx-embeddings is synchronous, wrap calls with asyncio.to_thread().
Handle the case where mlx-embeddings is not installed (optional dependency).
Apply the same query prefix logic as OllamaClient for mxbai models.
</task_description>
implementation:
approach: |
Create src/recall/embedding/mlx_provider.py with:
1. Lazy import of mlx_embeddings to handle missing dependency
2. MLXProvider class implementing EmbeddingProvider protocol
3. Model/tokenizer loading in __init__ or lazy on first use
4. asyncio.to_thread() wrapper for sync mlx calls
5. Query prefix handling matching OllamaClient behavior
key_points:
- point: "Lazy import of mlx_embeddings"
details: "Import inside methods to gracefully handle ImportError"
reference: "src/recall/embedding/mlx_provider.py"
- point: "asyncio.to_thread() for async compatibility"
details: "Wrap sync mlx_embeddings.generate() calls for async interface"
reference: "src/recall/embedding/mlx_provider.py"
- point: "Query prefix for mxbai models"
details: "Apply EMBED_PREFIX when is_query=True, same as OllamaClient"
reference: "src/recall/embedding/ollama.py:203-207"
- point: "Batch processing with configurable batch_size"
details: "Process texts in batches, matching OllamaClient.embed_batch signature"
reference: "src/recall/embedding/ollama.py:221-280"
code_quality:
python:
full_quality_pipeline:
command: "cd /Users/harrison/Documents/Github/recall && uv run ruff check src/recall/embedding/mlx_provider.py && uv run ruff format src/recall/embedding/mlx_provider.py"
exit_on_failure: true
commit:
type: "feat"
message: "add MLXProvider embedding backend for Apple Silicon"
files:
- "src/recall/embedding/mlx_provider.py"
- "src/recall/embedding/__init__.py"
- "tests/unit/test_mlx_provider.py"
status: "completed"
execution_history:
- attempt_number: "1"
commit_verification:
found: true
hash: 7d6f2e6
message: 'feat: add MLXProvider embedding backend for Apple Silicon'
- attempt_number: "1"
agent: python-pro
verdict: GREEN
agent_output: '{"errors":[],"files_modified":["src/recall/embedding/mlx_provider.py","src/recall/embedding/__init__.py","tests/unit/test_mlx_provider.py"],"metadata":{"branch":"feature/hybrid_mlx_embeddings","commit_hash":"7d6f2e6","test_file":"tests/unit/test_mlx_provider.py","tests_passed":26},"output":"## Task Completed: Create MLXProvider embedding backend\n\n### Files Created/Modified:\n1. **src/recall/embedding/mlx_provider.py** (new)\n - MLXProvider class implementing EmbeddingProvider protocol\n - Lazy import of mlx_embeddings to handle missing dependency gracefully\n - asyncio.to_thread() wrapper for sync MLX calls\n - Query prefix handling for mxbai models (matching OllamaClient behavior)\n - Batch processing with configurable batch_size\n - MLXNotAvailableError for graceful dependency handling\n\n2. **src/recall/embedding/__init__.py** (modified)\n - Added MLXProvider and MLXNotAvailableError to exports\n\n3. **tests/unit/test_mlx_provider.py** (new)\n - 26 comprehensive unit tests covering:\n - Initialization and defaults\n - Protocol conformance\n - Missing dependency handling\n - Single embed with/without query prefix\n - Batch embedding with batching\n - Context manager lifecycle\n - Lazy model loading behavior\n - Module exports\n\n### Key Implementation Details:\n- Uses `asyncio.to_thread()` to wrap sync mlx_embeddings calls for async interface\n- Lazy loads model on first embed call to avoid startup overhead\n- Applies EMBED_PREFIX for mxbai models when is_query=True (same as OllamaClient)\n- Default model: `mlx-community/mxbai-embed-large-v1`\n- Handles both single and batch embedding results\n- Resource cleanup in close() clears model references for garbage collection\n\n### Commit:\n`feat: add MLXProvider embedding backend for Apple Silicon` (7d6f2e6)","status":"success","summary":"Created MLXProvider embedding backend for Apple Silicon with full EmbeddingProvider protocol compliance, lazy model loading, query prefix support for mxbai models, and comprehensive test coverage (26 tests)."}'
qc_feedback: |-
[code-reviewer] MLXProvider implementation is complete and correct. The class implements EmbeddingProvider protocol with all required methods (embed, embed_batch, close, __aenter__, __aexit__). Uses mlx-embeddings library with asyncio.to_thread() wrapping for async compatibility. Lazy loading of model on first use. Query prefix handling for mxbai models matches OllamaClient behavior. Graceful ImportError handling via MLXNotAvailableError. Properly exported from embedding/__init__.py. All 26 unit tests pass. No TODO comments in production code.
[python-pro] MLXProvider implementation fully satisfies all success criteria. The class correctly implements the EmbeddingProvider protocol with lazy model loading, asyncio.to_thread() wrapping for async compatibility, query prefix handling for mxbai models, batch processing with configurable batch_size, and graceful ImportError handling via MLXNotAvailableError. All 26 tests pass, and the class is properly exported from embedding/__init__.py.
[architect-reviewer] MLXProvider implementation is complete and correct. The class properly implements the EmbeddingProvider protocol with all required methods (embed, embed_batch, close, __aenter__, __aexit__). Implementation correctly uses mlx-embeddings library with lazy loading via _ensure_loaded(), wraps synchronous mlx_embeddings calls with asyncio.to_thread() for async compatibility, accepts model parameter with the specified default 'mlx-community/mxbai-embed-large-v1', applies query prefix for mxbai models when is_query=True (matching OllamaClient behavior), supports batch processing with configurable batch_size, gracefully handles ImportError via MLXNotAvailableError, and is properly exported from embedding/__init__.py. All 26 tests pass, no TODO comments found in production code, and all imports resolve correctly.
[ml-engineer] MLXProvider embedding backend successfully implemented with full EmbeddingProvider protocol compliance. All 10 success criteria pass: the class implements the protocol, uses mlx-embeddings with asyncio.to_thread() for async wrapping, accepts custom model parameter with correct default, applies query prefix for mxbai models, handles batch processing with configurable batch_size, gracefully handles ImportError via lazy imports and MLXNotAvailableError, and is properly exported from the embedding package. No TODO comments found. All 26 unit tests pass and imports resolve correctly. The implementation correctly follows the established OllamaClient patterns for query prefix handling and batch processing.
timestamp: "2026-01-14T11:54:55Z"
completed_date: "2026-01-14"
# ============================================
# TASK 5: Create Provider Factory
# ============================================
- task_number: "5"
name: "Create embedding provider factory function"
agent: "python-pro"
files:
- "src/recall/embedding/factory.py"
- "src/recall/embedding/__init__.py"
depends_on: [1, 2, 3, 4]
success_criteria:
- "create_embedding_provider() factory function created"
- "Factory accepts backend parameter of type EmbeddingBackend"
- "Factory returns EmbeddingProvider instance"
- "Factory instantiates OllamaProvider when backend='ollama'"
- "Factory instantiates MLXProvider when backend='mlx'"
- "Factory raises ValueError for unknown backend"
- "Factory raises ImportError with helpful message if mlx-embeddings not installed for mlx backend"
- "Factory exported from embedding/__init__.py"
- "No TODO comments in production code"
- "All imports resolve"
test_commands:
- "cd /Users/harrison/Documents/Github/recall && uv run pytest tests/unit/test_embedding_factory.py -v"
- "cd /Users/harrison/Documents/Github/recall && uv run python -c 'from recall.embedding import create_embedding_provider'"
runtime_metadata:
dependency_checks:
- command: "cd /Users/harrison/Documents/Github/recall && uv run python -c 'from recall.embedding.ollama import OllamaProvider'"
description: "Verify OllamaProvider exists (Task 3)"
- command: "cd /Users/harrison/Documents/Github/recall && uv run python -c 'from recall.embedding.mlx_provider import MLXProvider'"
description: "Verify MLXProvider exists (Task 4)"
documentation_targets: []
description: |
<dependency_verification priority="execute_first">
<commands>
cd /Users/harrison/Documents/Github/recall && uv run python -c "from recall.embedding.ollama import OllamaProvider"
cd /Users/harrison/Documents/Github/recall && uv run python -c "from recall.embedding.mlx_provider import MLXProvider"
</commands>
</dependency_verification>
<task_description>
Create factory function that instantiates the correct embedding provider
based on the backend configuration. This centralizes provider creation
and handles the conditional import of MLXProvider.
</task_description>
implementation:
approach: |
Create src/recall/embedding/factory.py with:
1. create_embedding_provider(backend, **kwargs) function
2. Match on backend value to instantiate correct provider
3. Pass through kwargs (host, model, timeout) to provider
4. Helpful error messages for missing dependencies
key_points:
- point: "create_embedding_provider factory function"
details: "Single entry point for provider instantiation"
reference: "src/recall/embedding/factory.py"
- point: "Backend selection via match statement"
details: "Python 3.10+ match/case for clean dispatch"
reference: "src/recall/embedding/factory.py"
- point: "Helpful ImportError for missing mlx-embeddings"
details: "Guide user to install mlx-embeddings if mlx backend selected"
reference: "src/recall/embedding/factory.py"
code_quality:
python:
full_quality_pipeline:
command: "cd /Users/harrison/Documents/Github/recall && uv run ruff check src/recall/embedding/factory.py && uv run ruff format src/recall/embedding/factory.py"
exit_on_failure: true
commit:
type: "feat"
message: "add create_embedding_provider factory function"
files:
- "src/recall/embedding/factory.py"
- "src/recall/embedding/__init__.py"
- "tests/unit/test_embedding_factory.py"
status: "completed"
execution_history:
- attempt_number: "1"
commit_verification:
found: true
hash: 3147bdc
message: 'feat: add create_embedding_provider factory function'
- attempt_number: "1"
agent: python-pro
verdict: GREEN
agent_output: '{"files_modified":["src/recall/embedding/factory.py","src/recall/embedding/__init__.py","tests/unit/test_embedding_factory.py"],"output":"Created factory function that centralizes embedding provider instantiation based on backend configuration.\n\n**Files Created/Modified:**\n1. `src/recall/embedding/factory.py` - New factory module with `create_embedding_provider()` function\n2. `src/recall/embedding/__init__.py` - Added export of `create_embedding_provider`\n3. `tests/unit/test_embedding_factory.py` - 16 comprehensive unit tests\n\n**Factory Function Features:**\n- Takes `EmbeddingBackend` type (''ollama'' or ''mlx'') as first argument\n- Uses Python 3.10+ match/case for clean dispatch\n- Passes through kwargs (host, model, timeout) to OllamaProvider\n- Passes mlx_model to MLXProvider\n- Lazy import of MLXProvider to handle missing mlx-embeddings gracefully\n- Helpful ImportError message guides users to install mlx-embeddings on Apple Silicon\n- ValueError for unknown backends lists valid options\n\n**Architectural Decisions:**\n- Factory pattern chosen to centralize provider instantiation and handle conditional imports\n- Lazy import inside match block prevents ImportError at module load time\n- Type hints ensure compile-time safety with EmbeddingBackend Literal type\n- Returns EmbeddingProvider protocol type for duck typing flexibility\n\n**Test Coverage:**\n- OllamaProvider creation with default and custom parameters (5 tests)\n- MLXProvider creation with mocked imports (3 tests)\n- Unknown backend error handling (2 tests)\n- Protocol conformance verification (2 tests)\n- Package export verification (2 tests)\n- Type hint acceptance tests (2 tests)\n\n**Commit:** `3147bdc feat: add create_embedding_provider factory function`","status":"success","summary":"Created create_embedding_provider factory function with tests"}'
qc_feedback: |-
[code-reviewer] The create_embedding_provider factory function has been successfully implemented with all required functionality. The factory accepts EmbeddingBackend ('ollama' or 'mlx'), returns EmbeddingProvider instances, uses Python 3.10+ match/case for dispatch, handles missing mlx-embeddings gracefully with helpful error messages, raises ValueError for unknown backends, is exported from embedding/__init__.py, has comprehensive test coverage (16 passing tests), and contains no TODO comments.
[python-integration-specialist] Factory function implementation is complete and well-designed. The `create_embedding_provider()` function in `src/recall/embedding/factory.py` correctly implements backend selection using Python 3.10+ match/case, accepts `EmbeddingBackend` type parameter, returns `EmbeddingProvider` instances, handles lazy import of MLXProvider with helpful ImportError, raises ValueError for unknown backends, and is properly exported from `__init__.py`. All 16 unit tests pass, and the import verification succeeds. No TODO comments in production code.
[architect-reviewer] The implementation of the embedding provider factory function is complete and correct. All success criteria are satisfied:
1. **Factory function created** at `src/recall/embedding/factory.py` with `create_embedding_provider()` function
2. **Proper type handling**: Accepts `EmbeddingBackend` (Literal["ollama", "mlx"]) as the backend parameter
3. **Returns EmbeddingProvider**: Return type annotation is `EmbeddingProvider` protocol
4. **OllamaProvider instantiation**: Lines 76-86 handle "ollama" backend case
5. **MLXProvider instantiation**: Lines 88-100 handle "mlx" backend with lazy import
6. **ValueError for unknown backends**: Lines 102-108 raise ValueError with helpful message listing valid options
7. **ImportError with helpful message**: Lines 92-97 catch ImportError and re-raise with guidance about installing mlx-embeddings on Apple Silicon
8. **Exported from __init__.py**: Line 14 imports and line 24 adds to `__all__`
9. **No TODO comments**: Grep search confirms no TODO comments in factory.py
10. **All imports resolve**: Test commands passed successfully
**Architectural Decisions:**
- Factory pattern centralizes provider creation, enabling easy switching between backends
- Lazy import of MLXProvider (inside match block) prevents ImportError at module load time when mlx-embeddings isn't installed
- Match/case statement provides clean dispatch and exhaustive pattern matching
- TYPE_CHECKING guard for EmbeddingProvider import avoids circular dependency issues
**Test Coverage:**
All 16 tests pass covering OllamaProvider creation (5 tests), MLXProvider creation with mocks (3 tests), error handling (4 tests), protocol conformance (2 tests), and package exports (2 tests).
**Prior Art Justification:** The prior art referenced in pattern intelligence consists of previous commits that implemented the prerequisite components (EmbeddingProvider protocol, OllamaProvider refactor, MLXProvider, EmbeddingBackend config). This factory function is a NEW integration layer that ties those existing components together - it doesn't duplicate any prior work. The factory pattern is the standard way to centralize object creation and handle conditional imports (lazy MLX loading). No existing factory function existed in the codebase; this task creates the missing piece that allows consumers to easily instantiate providers based on configuration.
[python-schema-architect] Factory function implementation is complete and correct. The create_embedding_provider() function in src/recall/embedding/factory.py:
- Accepts EmbeddingBackend type parameter ('ollama' or 'mlx')
- Returns EmbeddingProvider protocol instance
- Uses Python 3.10+ match/case for clean backend dispatch
- Correctly instantiates OllamaProvider with host, model, timeout kwargs
- Correctly instantiates MLXProvider with mlx_model parameter
- Uses lazy import for MLXProvider to handle missing mlx-embeddings gracefully
- Provides helpful ImportError message for missing mlx-embeddings (includes pip install command and Apple Silicon note)
- Raises ValueError for unknown backends with list of valid options
- Exported from embedding/__init__.py and included in __all__
- No TODO comments in production code
- All imports resolve correctly
- 16 comprehensive unit tests all passing
timestamp: "2026-01-14T12:04:04Z"
completed_date: "2026-01-14"
# ============================================
# TASK 6: Update HybridStore to use Factory
# ============================================
- task_number: "6"
name: "Update HybridStore.create() to use provider factory"
agent: "python-pro"
files:
- "src/recall/storage/hybrid.py"
depends_on: [1, 2, 5]
success_criteria:
- "HybridStore.create() accepts embedding_backend parameter"
- "HybridStore.create() calls create_embedding_provider() factory"
- "HybridStore.__init__ accepts embedding_client typed as EmbeddingProvider"
- "Default embedding_backend is 'ollama' for backward compatibility"
- "All existing HybridStore tests pass without modification"
- "No TODO comments in production code"
- "All imports resolve"
test_commands:
- "cd /Users/harrison/Documents/Github/recall && uv run pytest tests/unit/test_hybrid_store.py -v"
- "cd /Users/harrison/Documents/Github/recall && uv run pytest tests/unit/ -v -k hybrid"
runtime_metadata:
dependency_checks:
- command: "cd /Users/harrison/Documents/Github/recall && uv run python -c 'from recall.embedding import create_embedding_provider'"
description: "Verify factory exists (Task 5)"
- command: "cd /Users/harrison/Documents/Github/recall && uv run python -c 'from recall.config import EmbeddingBackend'"
description: "Verify EmbeddingBackend type exists (Task 2)"
documentation_targets: []
description: |
<dependency_verification priority="execute_first">
<commands>
cd /Users/harrison/Documents/Github/recall && uv run python -c "from recall.embedding import create_embedding_provider"
cd /Users/harrison/Documents/Github/recall && uv run python -c "from recall.config import EmbeddingBackend"
</commands>
</dependency_verification>
<task_description>
Update HybridStore to use the new provider factory instead of directly
instantiating OllamaClient. Add embedding_backend parameter to create()
factory method. Update type hints to use EmbeddingProvider protocol.
</task_description>
implementation:
approach: |
Modify src/recall/storage/hybrid.py:
1. Import EmbeddingProvider, create_embedding_provider, EmbeddingBackend
2. Add embedding_backend parameter to create() with default='ollama'
3. Replace OllamaClient() with create_embedding_provider() call
4. Update __init__ type hint from OllamaClient to EmbeddingProvider
key_points:
- point: "HybridStore.create() accepts embedding_backend parameter"
details: "New parameter with default='ollama' for backward compatibility"
reference: "src/recall/storage/hybrid.py:89-140"
- point: "Factory call replaces direct OllamaClient instantiation"
details: "embedding_client = create_embedding_provider(backend=embedding_backend, ...)"
reference: "src/recall/storage/hybrid.py:126-129"
- point: "Type hint update to EmbeddingProvider"
details: "embedding_client: EmbeddingProvider in __init__"
reference: "src/recall/storage/hybrid.py:72"
code_quality:
python:
full_quality_pipeline:
command: "cd /Users/harrison/Documents/Github/recall && uv run ruff check src/recall/storage/hybrid.py && uv run ruff format src/recall/storage/hybrid.py"
exit_on_failure: true
commit:
type: "refactor"
message: "HybridStore uses embedding provider factory"
files:
- "src/recall/storage/hybrid.py"
status: "completed"
execution_history:
- attempt_number: "1"
commit_verification:
found: true
hash: 5d83f81
message: 'refactor: HybridStore uses embedding provider factory'
- attempt_number: "2"
commit_verification:
found: true
hash: 5d83f81
message: 'refactor: HybridStore uses embedding provider factory'
- attempt_number: "3"
commit_verification:
found: true
hash: 5d83f81
message: 'refactor: HybridStore uses embedding provider factory'
- attempt_number: "1"
agent: python-pro
verdict: GREEN
agent_output: '{"errors":[],"files_modified":[],"metadata":{"already_committed":true,"commit_hash":"5d83f81","commit_message":"refactor: HybridStore uses embedding provider factory"},"output":"Task 6 is already complete. The HybridStore has been updated to use the embedding provider factory:\n\n1. **Imports added** (lines 22-24):\n - `EmbeddingBackend` from `recall.config`\n - `EmbeddingProvider` and `create_embedding_provider` from `recall.embedding`\n\n2. **Type hint updated** (line 73):\n - `embedding_client: EmbeddingProvider` in `__init__`\n\n3. **Factory method updated** (lines 102-103):\n - Added `embedding_backend: EmbeddingBackend = \"ollama\"` parameter\n - Added `mlx_model: str = \"mlx-community/mxbai-embed-large-v1\"` parameter\n\n4. **Factory call replaces direct instantiation** (lines 134-139):\n ```python\n embedding_client = create_embedding_provider(\n backend=embedding_backend,\n host=ollama_host,\n model=ollama_model,\n mlx_model=mlx_model,\n )\n ```\n\nAlready committed as: `refactor: HybridStore uses embedding provider factory` (5d83f81)","status":"success","summary":"HybridStore already updated to use embedding provider factory (commit 5d83f81)"}'
qc_feedback: |-
[code-reviewer] Task 6 has been successfully completed. The HybridStore has been properly updated to use the embedding provider factory pattern:
1. **Factory method signature** (lines 93-104): `create()` now accepts `embedding_backend: EmbeddingBackend = "ollama"` parameter with proper default for backward compatibility.
2. **Factory function integration** (lines 134-139): Direct OllamaClient instantiation has been replaced with `create_embedding_provider(backend=embedding_backend, host=ollama_host, model=ollama_model, mlx_model=mlx_model)`.
3. **Type hint update** (line 73): `embedding_client: EmbeddingProvider` is correctly typed using the protocol interface.
4. **Proper imports** (lines 22-23): `EmbeddingBackend` from `recall.config` and `EmbeddingProvider, create_embedding_provider` from `recall.embedding` are correctly imported.
5. **All 37 unit tests pass** without modification, confirming backward compatibility.
The commit (5d83f81) was already made with the correct message: "refactor: HybridStore uses embedding provider factory".
[python-integration-specialist] Agent python-integration-specialist failed: failed to parse QC response as JSON: no complete JSON object found in output
[architect-reviewer] All success criteria verified. HybridStore.create() properly accepts the embedding_backend parameter (line 102) with default value 'ollama' for backward compatibility. The factory method correctly calls create_embedding_provider() (lines 134-139) instead of directly instantiating OllamaClient. The __init__ method's embedding_client parameter is typed as EmbeddingProvider (line 73). All 37 unit tests pass, imports resolve correctly, and no TODO comments exist in the production code. The commit (5d83f81) has been verified.
[python-schema-architect] Implementation successfully completed. HybridStore has been updated to use the embedding provider factory:
1. **Imports added correctly** (lines 22-23): `EmbeddingBackend` from `recall.config` and `EmbeddingProvider`, `create_embedding_provider` from `recall.embedding`
2. **Type hint updated** (line 73): `embedding_client: EmbeddingProvider` in `__init__`
3. **Factory method updated** (lines 102-103): Added `embedding_backend: EmbeddingBackend = "ollama"` parameter with default for backward compatibility, plus `mlx_model` parameter
4. **Factory call replaces direct instantiation** (lines 134-139): Uses `create_embedding_provider()` with all parameters passed through
All 37 unit tests pass, confirming backward compatibility is maintained. The commit was already made (5d83f81).
timestamp: "2026-01-14T13:17:12Z"
completed_date: "2026-01-14"
# ============================================
# TASK 7: Update MCP Server and CLI
# ============================================
- task_number: "7"
name: "Update MCP server to support embedding_backend config"
agent: "python-pro"
files:
- "src/recall/__main__.py"
depends_on: [2, 6]
success_criteria:
- "CLI argument --embedding-backend added with choices=['ollama', 'mlx']"
- "embedding_backend passed to HybridStore.create()"
- "RecallSettings.embedding_backend used as default when CLI arg not provided"
- "Startup log message indicates which embedding backend is active"
- "No TODO comments in production code"
- "All imports resolve"
test_commands:
- "cd /Users/harrison/Documents/Github/recall && uv run python -m recall --help | grep embedding-backend"
- "cd /Users/harrison/Documents/Github/recall && uv run pytest tests/integration/test_mcp_server.py -v"
runtime_metadata:
dependency_checks:
- command: "cd /Users/harrison/Documents/Github/recall && uv run python -c 'from recall.config import RecallSettings; print(RecallSettings().embedding_backend)'"
description: "Verify embedding_backend config exists (Task 2)"
documentation_targets: []
description: |
<dependency_verification priority="execute_first">
<commands>
cd /Users/harrison/Documents/Github/recall && uv run python -c "from recall.config import RecallSettings; print(RecallSettings().embedding_backend)"
</commands>
</dependency_verification>
<task_description>
Update the MCP server entry point to support the new embedding_backend
configuration. Add CLI argument and pass through to HybridStore.create().
Log which backend is being used at startup for debugging.
</task_description>
implementation:
approach: |
Modify src/recall/__main__.py:
1. Add --embedding-backend CLI argument with choices
2. Get default from RecallSettings.embedding_backend
3. Pass to HybridStore.create(embedding_backend=...)
4. Add startup log indicating active backend
key_points:
- point: "CLI argument --embedding-backend"
details: "argparse argument with choices=['ollama', 'mlx'], default from settings"
reference: "src/recall/__main__.py:235-278"
- point: "Pass embedding_backend to HybridStore.create()"
details: "HybridStore.create(..., embedding_backend=args.embedding_backend)"
reference: "src/recall/__main__.py:260-270"
- point: "Startup log message"
details: "logger.info(f'Using {args.embedding_backend} embedding backend')"
reference: "src/recall/__main__.py"
code_quality:
python:
full_quality_pipeline:
command: "cd /Users/harrison/Documents/Github/recall && uv run ruff check src/recall/__main__.py && uv run ruff format src/recall/__main__.py"
exit_on_failure: true
commit:
type: "feat"
message: "add --embedding-backend CLI option to MCP server"
files:
- "src/recall/__main__.py"
status: "completed"
execution_history:
- attempt_number: "1"
commit_verification:
found: true
hash: 111b2af
message: 'feat: add --embedding-backend CLI option to MCP server'
- attempt_number: "1"
agent: python-pro
verdict: GREEN
agent_output: '{"errors":[],"files_modified":["src/recall/__main__.py"],"metadata":{"commit_hash":"111b2af","lines_added":22,"lines_deleted":1},"output":"Successfully implemented --embedding-backend CLI option in src/recall/__main__.py:\n\n1. Added CLI arguments in parse_arguments():\n - --embedding-backend: choices=[''ollama'', ''mlx''], default from settings.embedding_backend\n - --mlx-model: for MLX model identifier when using mlx backend\n\n2. Updated initialize_components():\n - Added embedding_backend to configuration log message\n - Added dedicated startup log: logger.info(f''Using {args.embedding_backend} embedding backend'')\n - Pass embedding_backend and mlx_model to HybridStore.create()\n\n3. Updated module docstring to document new CLI options\n\n4. Verified with --help output showing:\n --embedding-backend {ollama,mlx}\n --mlx-model MLX_MODEL\n\nCommit: 111b2af - feat: add --embedding-backend CLI option to MCP server","status":"success","summary":"Added --embedding-backend CLI option to MCP server with mlx/ollama choices, startup logging, and pass-through to HybridStore.create()"}'
qc_feedback: |-
[code-reviewer] Implementation correctly adds --embedding-backend CLI option to MCP server. All success criteria are satisfied: CLI argument with choices=['ollama', 'mlx'] is present at lines 226-232, embedding_backend is passed to HybridStore.create() at line 294, default comes from RecallSettings.embedding_backend at line 229, and startup log message at line 283 indicates active backend. The implementation also includes related --mlx-model argument and updates the module docstring. Tests pass (50/50), help output confirms the argument is available, and commit was successfully created.
[python-pro] The implementation correctly adds --embedding-backend CLI option to the MCP server. All success criteria are satisfied: the CLI argument is properly defined with choices=['ollama', 'mlx'] (lines 226-232), defaults to settings.embedding_backend from RecallSettings, is passed to HybridStore.create() (line 294), and there's a clear startup log message (line 283). The implementation follows existing patterns in the codebase and properly integrates with the dependencies from config.py (EmbeddingBackend type) and hybrid.py (HybridStore.create() embedding_backend parameter). The --mlx-model argument is also included as a complementary option (lines 233-238).
[mcp-developer] The implementation correctly adds the --embedding-backend CLI option to the MCP server with all required functionality. The CLI argument (lines 226-232) supports choices=['ollama', 'mlx'] with the default sourced from RecallSettings.embedding_backend. The embedding_backend parameter is properly passed to HybridStore.create() (line 294) along with mlx_model (line 295). Startup logging is comprehensive with both a dedicated log message (line 283: "Using {args.embedding_backend} embedding backend") and inclusion in the configuration summary (line 281). All tests pass (50/50) including the --help verification showing the new argument. The commit was properly created as instructed (111b2af).
[backend-architect] All success criteria have been verified and passed. The implementation correctly adds the --embedding-backend CLI argument with choices=['ollama', 'mlx'], passes embedding_backend to HybridStore.create(), uses RecallSettings.embedding_backend as default when CLI arg not provided, and includes startup log messages indicating which embedding backend is active. Tests pass and implementation follows existing patterns.
timestamp: "2026-01-14T13:23:56Z"
completed_date: "2026-01-14"
# ============================================
# TASK 8: Integration Tests for Backend Switching
# ============================================
- task_number: "8"
name: "Add integration tests for embedding backend switching"
agent: "python-backend-tdd-agent"
files:
- "tests/integration/test_embedding_backends.py"
depends_on: [3, 4, 5, 6]
success_criteria:
- "Test verifies OllamaProvider produces valid embeddings"
- "Test verifies MLXProvider produces valid embeddings (skip if mlx-embeddings not installed)"
- "Test verifies both providers produce embeddings of same dimensionality"
- "Test verifies factory creates correct provider for each backend"
- "Test verifies HybridStore works with both backends"
- "Tests use pytest.mark.skipif for optional dependencies"
- "No TODO comments in test code"
test_commands:
- "cd /Users/harrison/Documents/Github/recall && uv run pytest tests/integration/test_embedding_backends.py -v"
runtime_metadata:
dependency_checks:
- command: "cd /Users/harrison/Documents/Github/recall && uv run python -c 'from recall.embedding import create_embedding_provider, OllamaProvider'"
description: "Verify embedding module exports"
documentation_targets: []
description: |
<dependency_verification priority="execute_first">
<commands>
cd /Users/harrison/Documents/Github/recall && uv run python -c "from recall.embedding import create_embedding_provider"
</commands>
</dependency_verification>
<task_description>
Create integration tests that verify both embedding backends work correctly
and produce compatible embeddings. Tests should gracefully skip MLX tests
if mlx-embeddings is not installed.
</task_description>
implementation:
approach: |
Create tests/integration/test_embedding_backends.py with:
1. Fixtures for each provider type
2. Tests for embedding generation (single and batch)
3. Tests for embedding dimensionality consistency
4. Tests for factory dispatch
5. pytest.mark.skipif for optional mlx-embeddings
key_points:
- point: "pytest.mark.skipif for MLX tests"
details: "Skip MLX tests if mlx-embeddings not installed"
reference: "tests/integration/test_embedding_backends.py"
- point: "Embedding dimensionality consistency test"
details: "Both providers should produce 1024-dim vectors for mxbai model"
reference: "tests/integration/test_embedding_backends.py"
- point: "HybridStore integration with both backends"
details: "Full store/recall cycle with each backend"
reference: "tests/integration/test_embedding_backends.py"
code_quality:
python:
full_quality_pipeline:
command: "cd /Users/harrison/Documents/Github/recall && uv run ruff check tests/integration/test_embedding_backends.py && uv run ruff format tests/integration/test_embedding_backends.py"
exit_on_failure: true
commit:
type: "test"
message: "add integration tests for embedding backend switching"
files:
- "tests/integration/test_embedding_backends.py"
status: "completed"
execution_history:
- attempt_number: "1"
commit_verification:
found: true
hash: 292ef18
message: 'test: add integration tests for embedding backend switching'
- attempt_number: "1"
agent: python-backend-tdd-agent
verdict: GREEN
agent_output: '{"errors":[],"files_modified":["tests/integration/test_embedding_backends.py"],"metadata":{"commit_hash":"292ef18","tests_passed":17,"tests_skipped":5,"tests_total":22},"output":"Created tests/integration/test_embedding_backends.py with comprehensive integration tests:\n\n## Test Categories:\n\n1. **TestFactoryDispatch** (6 tests)\n - Factory creates OllamaProvider correctly\n - Factory passes custom parameters to OllamaProvider\n - Factory creates MLXProvider (skipped if not available)\n - Factory passes mlx_model parameter (skipped if not available)\n - Factory raises ImportError with helpful message for missing mlx-embeddings\n - Factory raises ValueError for unknown backend\n\n2. **TestOllamaProviderMocked** (2 tests)\n - Single text embedding with mocked HTTP\n - Batch text embedding with mocked HTTP\n\n3. **TestMLXProviderMocked** (2 tests)\n - Single text embedding with mocked mlx_embeddings\n - Batch text embedding with mocked mlx_embeddings\n\n4. **TestEmbeddingDimensionality** (3 tests)\n - Ollama mxbai produces 1024-dim vectors\n - MLX mxbai produces 1024-dim vectors\n - Both backends produce same dimensionality\n\n5. **TestHybridStoreWithBothBackends** (4 tests)\n - HybridStore store/recall cycle with Ollama backend\n - HybridStore store/recall cycle with MLX backend\n - HybridStore.create() factory with ollama backend\n - HybridStore.create() factory with mlx backend\n\n6. **TestBackendSwitching** (2 tests)\n - Memories searchable after backend switch\n - Both backends implement EmbeddingProvider protocol\n\n7. **TestMLXRealBackend** (3 tests, skipped if mlx-embeddings not installed)\n - Real MLX embed single text\n - Real MLX embed batch\n - Real MLX query prefix handling\n\n## Test Results:\n- 17 passed\n- 5 skipped (MLX tests require Apple Silicon with mlx-embeddings installed)\n\n## Key Features:\n- pytest.mark.skipif for MLX tests when mlx-embeddings not installed\n- Proper mocking of both Ollama HTTP and MLX modules\n- Ephemeral stores for test isolation\n- Full HybridStore integration tests with both backends","status":"success","summary":"Created integration tests for embedding backend switching with 17 passing tests covering factory dispatch, embedding generation, dimensionality consistency, HybridStore integration, and backend switching"}'
qc_feedback: |-
[code-reviewer] All 7 success criteria verified. The test file tests/integration/test_embedding_backends.py is comprehensive with 22 tests (17 passed, 5 skipped for MLX). Tests cover OllamaProvider validation (TestOllamaProviderMocked), MLXProvider validation (TestMLXProviderMocked with mocked mlx-embeddings plus TestMLXRealBackend with skip decorator), dimensionality consistency (TestEmbeddingDimensionality verifies 1024-dim vectors), factory dispatch (TestFactoryDispatch), HybridStore integration (TestHybridStoreWithBothBackends), and proper pytest.mark.skipif usage for optional dependencies. No TODO comments found in the test code.
[python-backend-tdd-agent] Integration tests for embedding backend switching are comprehensive and complete. All 22 tests passed (17 executed, 5 appropriately skipped on non-Apple Silicon). The test file covers all required scenarios: OllamaProvider embedding generation, MLXProvider embedding generation with proper skip markers, dimensionality consistency verification (1024-dim), factory dispatch for both backends, and full HybridStore integration cycles. No TODO comments present.
[test-automator] All success criteria are met. The integration tests comprehensively cover embedding backend switching with 17 passing tests and 5 appropriately skipped tests (MLX tests requiring Apple Silicon). The test file is well-structured with proper fixtures, mocking, and pytest.mark.skipif decorators for optional dependencies.
[python-integration-specialist] Integration tests for embedding backend switching successfully implemented. All 22 tests pass (17 passed, 5 correctly skipped for MLX-only tests). The test file covers factory dispatch, embedding generation, dimensionality consistency, HybridStore integration, and backend switching. No TODO comments found.
timestamp: "2026-01-14T13:31:59Z"
completed_date: "2026-01-14"
# ============================================
# TASK 9: Documentation and Benchmark Script
# ============================================
- task_number: "9"
name: "Add benchmark script and update documentation"
agent: "python-pro"
files:
- "scripts/benchmark_embeddings.py"
- ".env.example"
depends_on: [7, 8]
success_criteria:
- "benchmark_embeddings.py script compares Ollama vs MLX latency"
- "Script outputs average latency, p95, p99 for both backends"
- "Script supports --iterations and --batch-size arguments"
- ".env.example updated with RECALL_EMBEDDING_BACKEND option"
- "Script handles missing mlx-embeddings gracefully"
- "No TODO comments in production code"
test_commands:
- "cd /Users/harrison/Documents/Github/recall && uv run python scripts/benchmark_embeddings.py --help"
- "cd /Users/harrison/Documents/Github/recall && uv run python scripts/benchmark_embeddings.py --iterations 3 --backend ollama"
runtime_metadata:
dependency_checks:
- command: "cd /Users/harrison/Documents/Github/recall && ls scripts/ 2>/dev/null || mkdir -p scripts"
description: "Ensure scripts directory exists"
documentation_targets: []
description: |
<dependency_verification priority="execute_first">
<commands>
cd /Users/harrison/Documents/Github/recall && ls scripts/ 2>/dev/null || mkdir -p scripts
</commands>
</dependency_verification>
<task_description>
Create a benchmark script to compare embedding latency between Ollama
and MLX backends. Update .env.example with the new configuration option.
This enables users to measure the actual performance improvement on their hardware.
</task_description>
implementation:
approach: |
1. Create scripts/benchmark_embeddings.py with argparse CLI
2. Measure embedding latency for configurable iterations
3. Calculate statistics (avg, p95, p99, min, max)
4. Pretty print comparison table
5. Update .env.example with RECALL_EMBEDDING_BACKEND
key_points:
- point: "Benchmark script with statistics"
details: "Measure and report avg, p95, p99 latency for both backends"
reference: "scripts/benchmark_embeddings.py"
- point: "CLI arguments for customization"
details: "--iterations, --batch-size, --backend for flexible benchmarking"
reference: "scripts/benchmark_embeddings.py"
- point: ".env.example update"
details: "Add RECALL_EMBEDDING_BACKEND=ollama with comment explaining options"
reference: ".env.example"
code_quality:
python:
full_quality_pipeline:
command: "cd /Users/harrison/Documents/Github/recall && uv run ruff check scripts/benchmark_embeddings.py && uv run ruff format scripts/benchmark_embeddings.py"
exit_on_failure: true
commit:
type: "feat"
message: "add embedding benchmark script and update .env.example"
files:
- "scripts/benchmark_embeddings.py"
- ".env.example"
status: "completed"
execution_history:
- attempt_number: "1"
commit_verification:
found: true
hash: 07e8c1b
message: 'feat: add embedding benchmark script and update .env.example'
- attempt_number: "1"
agent: python-pro
verdict: GREEN
agent_output: '{"errors":[],"files_modified":["scripts/benchmark_embeddings.py",".env.example"],"metadata":{"branch":"feature/hybrid_mlx_embeddings","commit_hash":"07e8c1b","task_id":"9"},"output":"Successfully completed Task 9: Add benchmark script and update documentation.\n\nCreated files:\n1. scripts/benchmark_embeddings.py - A comprehensive benchmark script that:\n - Compares embedding latency between Ollama and MLX backends\n - Reports statistics: avg, min, max, p95, p99, and stddev latency\n - CLI arguments: --backend, --iterations, --batch-size, --warmup, --json\n - Automatic backend availability detection\n - Pretty-printed comparison table with speedup summary\n - JSON output option for programmatic use\n\n2. Updated .env.example with new configuration options:\n - RECALL_EMBEDDING_BACKEND (ollama or mlx)\n - RECALL_MLX_MODEL (MLX model identifier)\n - Clear documentation explaining each option\n\nCommit: 07e8c1b - \"feat: add embedding benchmark script and update .env.example\"","status":"success","summary":"Created embedding benchmark script and updated .env.example with embedding backend configuration"}'
qc_feedback: |-
[code-reviewer] Task 9 completed successfully. The benchmark script is well-implemented with comprehensive statistics (avg, p95, p99, min, max, stddev), proper CLI arguments (--iterations, --batch-size, --backend, --warmup, --json), graceful MLX availability handling, and the .env.example properly documents the RECALL_EMBEDDING_BACKEND configuration option with clear explanations of both backends.
[performance-engineer] The benchmark script and .env.example update successfully implement all required functionality. The script compares Ollama vs MLX embedding latency with comprehensive statistics (avg, min, max, p95, p99, stddev), supports CLI arguments (--iterations, --batch-size, --warmup, --backend, --json), gracefully handles missing mlx-embeddings, and the .env.example includes RECALL_EMBEDDING_BACKEND documentation. No TODO comments in production code. Test commands passed successfully.
[python-pro] Task successfully completed. The benchmark script and .env.example updates meet all success criteria. The script provides comprehensive benchmarking with proper statistics (avg, p95, p99), CLI arguments (--iterations, --batch-size, --backend), and graceful MLX fallback handling. The .env.example correctly documents the RECALL_EMBEDDING_BACKEND option with clear explanations of both ollama and mlx choices.
[documentation-engineer] Implementation successfully meets all success criteria. The benchmark script compares Ollama vs MLX embedding latency with comprehensive statistics (avg, min, max, p95, p99, stddev), supports CLI customization via --iterations, --batch-size, --warmup, and --backend arguments, and gracefully handles missing mlx-embeddings via try/except ImportError. The .env.example has been properly updated with RECALL_EMBEDDING_BACKEND configuration option with clear documentation. Test commands passed: --help shows all expected arguments and the ollama benchmark ran successfully.
timestamp: "2026-01-14T13:38:49Z"
completed_date: "2026-01-14"