Development¶
📦 Dependencies¶
All Python dependencies are listed in requirements.txt. The new productivity tools use only standard library features:
| Tool | Python Packages | External Tools |
|---|---|---|
| TodoWrite | Standard library only | None |
| Edit Tool | Standard library only | None |
| Glob Search | Standard library (glob) |
None |
| Grep Search | Standard library (subprocess) |
ripgrep (required) |
| Error Handler | Standard library (functools) |
None |
| Git Safety | Standard library (subprocess) |
git |
| Plan Mode | Standard library (json, os) |
None |
| Background Tasks | Standard library (threading) |
None |
External Tools:
- ripgrep: Required by the
grep_searchtool — there is no fallback. Install via system package manager (see Recommended optional tools); without itgrep_searchreturns an error telling you to install it. Every other tool works without it.
Core Python Packages:
langgraph: Agent orchestration frameworklangchain,langchain-core: LLM abstraction layerlangchain-ollama: Ollama integrationlangchain-aws: AWS Bedrock integrationlangchain-openai: OpenAI integration (also used for Bedrock Mantle OpenAI/Responses protocols)langchain-anthropic: Anthropic integration (Bedrock Mantleanthropicprotocol)aws-bedrock-token-generator: Bearer-token auth for Bedrock Mantlemcp,mcp[cli]: Model Context Protocolollama: Local LLM supportboto3: AWS Bedrock/SageMakertiktoken: Token countingchromadb,faiss-cpu: Vector stores for RAGPyPDF2,python-docx: Document readersPygments: Code syntax highlightingprompt_toolkit: Interactive CLIbrave-search-python-client: Web searchcrawl4ai: Web crawling
🛠️ Development¶
Testing¶
The test suite uses pytest and is split into two tiers under tests/:
tests/unit/— fast, deterministic tests for pure logic (BM25, reasoning helpers, response parsing, subtask parsing, the tool error handler, git-safety command classification, file editing/search, bash timeout handling, and episodic-memory heuristics). No LLM, Ollama, or network required, so they run in seconds and don't need aconfig.yaml.tests/integration/— end-to-end tests that drive the real agent against a live Ollama server and the MCP subprocess (routing, tool calls, bash timeout, no silent empty turns). Marked with@pytest.mark.integrationand auto-skipped unless a resolvable runtime config exists (for exampleMNEMOAI_CONFIG=/path/to/config.yaml,~/.mnemoai/config/config.yaml, or the checkout fallbacksrc/mnemoai/utils/config.yaml) and the configured Ollama host is reachable.
# Install test dependencies
pip install -r requirements-dev.txt
# Run everything (integration auto-skips if Ollama/config aren't available)
python -m pytest
# Unit tier only (fast — good for CI and pre-commit)
python -m pytest tests/unit
# Integration tier only (requires Ollama running + a resolvable config.yaml)
MNEMOAI_CONFIG=/path/to/config.yaml python -m pytest -m integration
# Run a single file
python -m pytest tests/unit/test_bm25.py
When adding new code, keep import-time side effects independent of config.yaml so the module stays unit-testable.
CI. The .github/workflows/tests.yml workflow runs the unit tier (plus a ruff import-sort check) on every push and pull request across Python 3.11–3.13. The integration tier is not run in CI (it needs a live Ollama server) — run it locally before a release, per the checklist below.
Stability & Versioning¶
Mnemo AI follows Semantic Versioning. The public surface that versioning protects is:
- Config keys in
config.yaml(theMODEL_ID/VISION_MODEL_ID/RAG.EMBED_MODEL_IDfields, theENABLE_*/REQUIRE_*toggles, and the documented section keys). - Prompt keys in
prompts.yaml(SYSTEM_PROMPT,ROUTING_PROMPT,ORCHESTRATOR_PROMPT,AGGREGATOR_PROMPT,SUMMARY_SYSTEM_PROMPT,SUMMARY_TASK_PROMPT). These live inprompts.yaml, notconfig.yaml(keys left inconfig.yamlare ignored with a migration warning). - The
mcp.jsonschema for external MCP servers (mcpServerswithcommand/args/env/disabled). - CLI commands (
/config,/model,/params,/features,/mcp,/memory,/skills,/plan,/compact,/clear,/save,/load) and themnemoaiconsole command + its--no-verbose,--resume [SESSION_ID], and--continueflags. - The distribution/import name (
pip install mnemoai-assistant→import mnemoai).
Pre-1.0.0, minor releases may add features and occasionally adjust these. From 1.0.0 onward, a breaking change to any of the above bumps the major version; new backward-compatible features bump the minor; fixes bump the patch. Internal modules (anything under client/, server/, models/, utils/ not listed above) are not part of the public contract and may change between any releases. All changes are recorded in CHANGELOG.md.
Release Checklist¶
Before tagging a release:
- Unit tests + lint pass (also enforced by CI):
python -m pytest -m "not integration"andruff check --select I .. - Integration smoke test with a live model (
PYTHONPATH=src python -m pytest -m integration, or manually drive the app and verify). Prefer a capable model here — small local models (e.g. a 4B) are intermittently unreliable at tool-calling, so the tool-backed checks can flake; the suite passes deterministically on a strong model (e.g. Bedrock Claude Sonnet). Point the run at a specific config withMNEMOAI_CONFIG=/path/to/config.yamlif needed: - a greeting / simple Q&A returns a non-empty answer;
- a tool-backed query runs a tool (e.g. "list files here") and the
[⚙ …]marker fires; - with routing on, a multi-step task is decomposed (orchestrator) and completes;
- plan mode:
/planon → an edit/bash request is blocked;/planoff → it proceeds; - an external MCP tool (from
mcp.json) is callable. - Update
CHANGELOG.md— moveUnreleaseditems under the new version + date. - Bump
versioninpyproject.toml. - Build + validate:
uv buildthentwine check dist/*. - Tag
vX.Y.Z, push, thentwine upload dist/*(refreshes the PyPI description).
Adding New Tools¶
- Create tool file in
server/tools/:
from mcp.server.fastmcp import FastMCP
def register_your_tool(mcp: FastMCP):
@mcp.tool()
async def your_tool(param: str) -> str:
"""Tool description for the LLM."""
# Implementation
return result
- Register in
tools_manager.py:
Adding New File Readers¶
- Create reader in
server/tools/readers/:
async def read_your_format(path: str) -> str:
"""Read your custom format."""
# Implementation
return content
- Register in
fs_read.py:
Switching Model Providers¶
The application uses controller classes for centralized model management. To switch providers, just update config.yaml:
For LLM:
For Vision:
For Embeddings:
The controllers (llm_controller.py, vision_model_controller.py, embeddings_controller.py) handle all provider-specific initialization automatically.
Adding New Model Providers¶
- Update the appropriate controller in
models/:
def initialize_model(self):
if self.model_type == "your_provider":
# Your provider initialization
self.model = YourProviderModel(...)
- Add configuration in
config.yaml
📄 License¶
This project is licensed under the MIT License - see the LICENSE file for details.
🤝 Contributing¶
This is a personal development project. If you'd like to use or extend it, feel free to fork the repository and adapt it to your needs!
If you use this code in your own projects, attribution to the original repository is appreciated but not required.
🙏 Acknowledgments¶
- Built with LangGraph and LangChain
- Uses FastMCP for Model Context Protocol
- Powered by Ollama, Amazon Bedrock, and Amazon SageMaker AI