[build-system] requires = ["setuptools>=77"] build-backend = "setuptools.build_meta" [project] name = "darwin-memo" dynamic = ["version"] description = "Self-curating memory for LLM agents: MeMo-style external memory kept honest by survival-based selection instead of reward models or judges." readme = "README.md" requires-python = ">=3.10" license = "MIT" authors = [{ name = "Roger Simoes" }] # PyPI indexes these and nothing else. CITATION.cff and .zenodo.json carried # a better set for a while and it never reached the one file search uses. # "mcp" matters most: this package ships an MCP server, and without the # keyword a PyPI search for "mcp memory" does not surface it at all. keywords = [ "llm", "memory", "agents", "agent-memory", "long-term-memory", "memory-curation", "mcp", "model-context-protocol", "coding-agent", "agent-security", "memory-poisoning", "continual-learning", "survival-selection", ] classifiers = [ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: Science/Research", "Operating System :: OS Independent", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Typing :: Typed", ] dependencies = [] # Every range is bounded above. mcp 2.0.0 removed the module the server # imports, and an unbounded `mcp>=1.10` shipped a broken extra to anyone # who installed it; the ceilings below exist so the next such release is # a resolver message rather than a runtime failure in someone else's # environment. Each upper bound is the next major after a version # verified against the API this package actually calls, so raising one # means checking that surface, not bumping a number. [project.optional-dependencies] # Verified at 0.120.2: anthropic.Anthropic().messages.create. anthropic = ["anthropic>=0.40,<1"] # Verified at 2.53.0: openai.OpenAI(base_url=...).chat.completions.create. # The floor still reads 1.50 because that surface is unchanged since. openai = ["openai>=1.50,<3"] # Never imported by this package: retrieval takes any text -> list[float] # callable, and this extra only spares the user a second install line. embeddings = ["sentence-transformers>=3,<6"] organic = ["turbovec>=0.1", "numpy>=1.24"] # Floor verified empirically: 1.10.0 is the oldest release with both the # FastMCP `instructions` parameter and the (blocks, structured) call_tool # return shape the server and tests rely on. # # Ceiling added after mcp 2.0.0 removed `mcp.server.fastmcp` outright, so # an unbounded range shipped a broken server to anyone installing the # extra: the import in mcp_server.build_server raises ModuleNotFoundError # on every Python version. Supporting 2.x means porting to its new API; # until then the range is capped rather than left to resolve into # something that does not work. mcp = ["mcp>=1.10,<2"] dev = [ "pytest>=8,<10", "pytest-cov>=5,<8", # Ruff is pre-1.0 and treats minor bumps as breaking: 0.16 began # formatting Python inside markdown fences, which reflowed prose code # samples in this repo. Unbounded, the lint result changes with every # release and a branch goes red for reasons no commit caused, so the # ceiling is the next minor rather than the next major. "ruff>=0.8,<0.17", "mypy>=1.13,<3", "hypothesis>=6,<7", ] [project.scripts] darwin-memo = "darwin_memo.cli:main" darwin-memo-mcp = "darwin_memo.mcp_server:main" [project.urls] Homepage = "https://github.com/rogermsc/darwin-memo" Documentation = "https://github.com/rogermsc/darwin-memo/blob/main/docs/README.md" Changelog = "https://github.com/rogermsc/darwin-memo/blob/main/CHANGELOG.md" Issues = "https://github.com/rogermsc/darwin-memo/issues" Source = "https://github.com/rogermsc/darwin-memo" Paper = "https://github.com/rogermsc/darwin-memo/blob/main/paper/main.tex" [tool.setuptools.dynamic] version = { attr = "darwin_memo.__version__" } [tool.setuptools.packages.find] include = ["darwin_memo*"] [tool.setuptools.package-data] darwin_memo = ["py.typed", "data/demo_corpus/*.txt", "data/ui/**/*"] [tool.pytest.ini_options] testpaths = ["tests"] [tool.coverage.run] source = ["darwin_memo"] # Only the ANN backend is excluded: it needs the optional turbovec extra and # cannot run in default CI. The rest of the organic layer is pure-Python and # zero-dep, so it is covered like any other module (tests/test_organic.py) — # the old blanket `organic/*` omit hid three shipped modules behind a reason # that was only ever true of this one. omit = ["darwin_memo/organic/turbovec_backend.py"] [tool.coverage.report] show_missing = true fail_under = 80 [tool.ruff] line-length = 88 target-version = "py310" # Markdown is excluded because ruff >= 0.16 formats Python inside fenced # blocks, and prose code samples are aligned for reading, not for the # formatter: it moves a continuation comment under a long line to column # zero, where it reads as a separate statement. Documentation examples # are checked by running them (the CI examples step), not by reformatting # them in place. Excluded by glob rather than by pinning ruff, so the # behaviour does not depend on which version CI happens to resolve. extend-exclude = ["training", "*.md"] [tool.ruff.lint] select = ["E", "F", "W", "I", "UP", "B", "SIM", "RUF"] [tool.mypy] python_version = "3.10" strict = true files = ["darwin_memo", "tests"] [[tool.mypy.overrides]] module = [ "anthropic", "anthropic.*", "openai", "openai.*", "sentence_transformers", "sentence_transformers.*", "mcp", "mcp.*", # Distill arm (bench/distill); optional ML deps, no stubs shipped. "torch", "torch.*", "transformers", "transformers.*", "peft", "peft.*", "datasets", "datasets.*", # Organic layer (darwin_memo/organic); optional deps, absent in the lint env. "turbovec", "turbovec.*", "numpy", "numpy.*", ] ignore_missing_imports = true [[tool.mypy.overrides]] module = "tests.*" disallow_untyped_defs = false disallow_untyped_calls = false # When the [mcp] extra is absent, FastMCP resolves as Any and its tool # decorator cascades untyped-decorator errors; relax just this module so # contributors without the extra still get a clean strict run. [[tool.mypy.overrides]] module = "darwin_memo.mcp_server" disallow_untyped_decorators = false