pyproject.toml
Rama main · réplica de lectura del repositorio original.
[project]
name = "basic-memory"
dynamic = ["version"]
description = "Local-first knowledge management combining Zettelkasten with knowledge graphs"
readme = "README.md"
requires-python = ">=3.12"
license = { text = "AGPL-3.0-or-later" }
authors = [
{ name = "Basic Machines", email = "hello@basic-machines.co" }
]
dependencies = [
"sqlalchemy>=2.0.0",
"pyyaml>=6.0.1",
"typer>=0.9.0",
"aiosqlite>=0.20.0",
"greenlet>=3.1.1",
"pydantic[email,timezone]>=2.12.0",
"mcp>=2,<3",
"pydantic-settings>=2.6.1",
"loguru>=0.7.3",
"pyright>=1.1.390",
"markdown-it-py>=3.0.0",
"python-frontmatter>=1.1.0",
"rich>=13.9.4",
"unidecode>=1.3.8",
"dateparser>=1.2.0",
"watchfiles>=1.0.4",
"fastapi[standard]==0.162.0",
"alembic>=1.14.1",
"pillow>=11.1.0",
"pybars3>=0.9.7",
"fastmcp==4.1.3",
"pyjwt>=2.15.0",
"python-dotenv>=1.1.0",
"pytest-aio>=1.9.0",
"aiofiles>=24.1.0",
"asyncpg>=0.30.0",
"pytest-asyncio>=1.2.0",
"psycopg==3.3.1",
"sniffio>=1.3.1",
"anyio>=4.10.0",
"httpx>=0.28.0",
"fastembed>=0.7.4",
"sqlite-vec>=0.1.6",
"openai>=1.100.2",
# The fastapi extra lets read-cache tests instrument the app as production does.
"logfire[fastapi]>=4.19.0",
"psutil>=5.9.0",
# uvloop's C event loop has no self._ready.popleft() codepath, so the
# asyncpg engine-dispose race ("IndexError: pop from an empty deque") that
# crashes the Postgres backend cannot fire under it. Not available on Windows.
"uvloop>=0.21.0; sys_platform != 'win32'",
# Cross-platform advisory file lock (already resolved transitively via
# huggingface-hub; declared directly since the hook flush path imports it).
# Serializes concurrent `bm hook flush` runs so a stale sweep can't overwrite
# an artifact without a sibling flush's just-retired event.
"filelock>=3.12",
"fastapi-redis-sdk==0.8.1",
"pathspec>=1.1.1,<2",
]
[project.optional-dependencies]
# Explicit opt-in: default local and OpenAI embeddings do not need this SDK.
# Preserve the Python 3.14-compatible range; 1.92 introduced an incompatible Rust bridge.
litellm = [
"litellm>=1.91.5,<1.92.0",
]
milvus = [
"pymilvus>=3.0.0,<4; sys_platform == 'win32'",
"pymilvus[milvus-lite]>=3.0.0,<4; sys_platform != 'win32'",
]
redis = [
"redis>=8.0.0,<9",
]
# Native PDF extraction for document ingestion. Optional so the default install
# stays parser-free; the worker records the installed version in run identity.
pdf = [
"pdf-inspector>=0.2.6,<2",
]
documents = [
"markitdown[docx,pptx]>=0.1.7,<0.2",
# Footnote parsing for the document page-citation tests.
"mdit-py-plugins>=0.6.1",
]
[project.urls]
Homepage = "https://github.com/basicmachines-co/basic-memory"
Repository = "https://github.com/basicmachines-co/basic-memory"
Documentation = "https://github.com/basicmachines-co/basic-memory#readme"
[project.scripts]
basic-memory = "basic_memory.cli.main:app"
bm = "basic_memory.cli.main:app"
[build-system]
requires = ["hatchling", "uv-dynamic-versioning>=0.7.0"]
build-backend = "hatchling.build"
[tool.pytest.ini_options]
pythonpath = ["src", "tests"]
# plugins/ carries the co-located uv hook-script tests (one per script).
testpaths = ["tests", "test-int", "plugins"]
asyncio_mode = "strict"
asyncio_default_fixture_loop_scope = "function"
# Any test hanging >120s fails with a stack dump instead of stalling the CI job
# until the runner times out (the FastMCP/asyncpg cleanup-hang family).
timeout = 120
timeout_method = "thread"
filterwarnings = [
"ignore:The @wait_container_is_ready decorator is deprecated.*:DeprecationWarning:testcontainers\\.core\\.waiting_utils",
"ignore:The default datetime adapter is deprecated as of Python 3\\.12.*:DeprecationWarning:aiosqlite\\.core",
"ignore:codecs\\.open\\(\\) is deprecated\\. Use open\\(\\) instead\\.:DeprecationWarning:frontmatter",
"ignore:Parsing dates involving a day of month without a year specified is ambiguous.*:DeprecationWarning:dateparser\\.utils\\.strptime",
]
markers = [
"benchmark: Performance benchmark tests (deselect with '-m \"not benchmark\"')",
"slow: Slow-running tests (deselect with '-m \"not slow\"')",
"postgres: Tests that run against Postgres backend (deselect with '-m \"not postgres\"')",
"redis: Tests that run against a real Redis server",
"windows: Windows-specific tests (deselect with '-m \"not windows\"')",
"smoke: Fast end-to-end smoke tests for MCP flows",
"semantic: Tests requiring semantic dependencies (fastembed, sqlite-vec, openai)",
"real_embedder: Tests that exercise the real FastEmbed provider instead of the test embedder",
"live: Tests that call external provider APIs and require explicit opt-in",
]
[tool.ruff]
extend-exclude = ["*.md"]
line-length = 100
target-version = "py312"
[tool.ruff.lint]
# Ruff 0.16 expanded its defaults; preserve the repository's established lint baseline.
select = ["E4", "E7", "E9", "F"]
[dependency-groups]
dev = [
# The fastapi extra lets read-cache tests instrument the app as production does.
"logfire[fastapi]>=4.19.0",
"icecream>=2.1.3",
"pytest>=8.3.4",
"pytest-cov>=4.1.0",
"pytest-mock>=3.12.0",
"pytest-asyncio>=0.24.0",
"pytest-xdist>=3.0.0",
"ruff>=0.16.0",
"freezegun>=1.5.5",
"testcontainers[postgres]>=4.0.0",
"redis>=8.0.0,<9",
"pdf-inspector>=0.2.6,<2",
"psycopg>=3.2.0",
"pyright>=1.1.408",
"pytest-testmon>=2.2.0",
"ty>=0.0.64",
"cst-lsp>=0.1.3",
"libcst>=1.8.6",
"pytest-timeout>=2.4.0",
"pytest-split>=0.11.0",
"markitdown[docx,pptx]>=0.1.7,<0.2",
# Footnote parsing for the document page-citation tests.
"mdit-py-plugins>=0.6.1",
]
[tool.hatch.version]
source = "uv-dynamic-versioning"
# Explicit resources only: never ship integration venvs, caches, or test data.
[tool.hatch.build.targets.wheel.force-include]
"integrations/tau/Basic Memory.py" = "basic_memory/data/tau/extension/Basic Memory.py"
"integrations/tau/extension.py" = "basic_memory/data/tau/extension/extension.py"
"integrations/tau/bridge.py" = "basic_memory/data/tau/extension/bridge.py"
"integrations/tau/continuity.py" = "basic_memory/data/tau/extension/continuity.py"
"integrations/tau/knowledge.py" = "basic_memory/data/tau/extension/knowledge.py"
"integrations/tau/privacy.py" = "basic_memory/data/tau/extension/privacy.py"
"integrations/tau/results.py" = "basic_memory/data/tau/extension/results.py"
"integrations/tau/pyproject.toml" = "basic_memory/data/tau/extension/pyproject.toml"
"integrations/tau/uv.lock" = "basic_memory/data/tau/extension/uv.lock"
"integrations/tau/README.md" = "basic_memory/data/tau/extension/README.md"
"integrations/tau/schemas" = "basic_memory/data/tau/extension/schemas"
"integrations/tau/prompts" = "basic_memory/data/tau/prompts"
# Distributed skills, for hosts that load SKILL.md files from the installed package
# (Cloud agents). Same set as the release archives: internal skills, evals/ and
# agents/ stay out. tests/test_skills_dist.py fails when this list drifts.
# Skills the Tau mapping below also copies are keyed by SKILL.md: TOML keys are unique.
"skills/memory-agents" = "basic_memory/data/skills/memory-agents"
"skills/memory-capture" = "basic_memory/data/skills/memory-capture"
"skills/memory-comark" = "basic_memory/data/skills/memory-comark"
"skills/memory-continue/SKILL.md" = "basic_memory/data/skills/memory-continue/SKILL.md"
"skills/memory-curate" = "basic_memory/data/skills/memory-curate"
"skills/memory-doctor" = "basic_memory/data/skills/memory-doctor"
"skills/memory-defrag" = "basic_memory/data/skills/memory-defrag"
"skills/memory-ingest" = "basic_memory/data/skills/memory-ingest"
"skills/memory-lifecycle" = "basic_memory/data/skills/memory-lifecycle"
"skills/memory-literary-analysis" = "basic_memory/data/skills/memory-literary-analysis"
"skills/memory-metadata-search" = "basic_memory/data/skills/memory-metadata-search"
"skills/memory-notes/SKILL.md" = "basic_memory/data/skills/memory-notes/SKILL.md"
"skills/memory-okf" = "basic_memory/data/skills/memory-okf"
"skills/memory-onboarding/SKILL.md" = "basic_memory/data/skills/memory-onboarding/SKILL.md"
"skills/memory-onboarding/references" = "basic_memory/data/skills/memory-onboarding/references"
"skills/memory-quest/SKILL.md" = "basic_memory/data/skills/memory-quest/SKILL.md"
"skills/memory-reflect" = "basic_memory/data/skills/memory-reflect"
"skills/memory-research" = "basic_memory/data/skills/memory-research"
"skills/memory-schema/SKILL.md" = "basic_memory/data/skills/memory-schema/SKILL.md"
"skills/memory-start" = "basic_memory/data/skills/memory-start"
"skills/memory-tasks/SKILL.md" = "basic_memory/data/skills/memory-tasks/SKILL.md"
"integrations/tau/skills/basic-memory-setup" = "basic_memory/data/tau/skills/basic-memory-setup"
"skills/memory-continue" = "basic_memory/data/tau/skills/memory-continue"
"skills/memory-tasks" = "basic_memory/data/tau/skills/memory-tasks"
"skills/memory-notes" = "basic_memory/data/tau/skills/memory-notes"
"skills/memory-schema" = "basic_memory/data/tau/skills/memory-schema"
"integrations/pi/extensions" = "basic_memory/data/pi/package/extensions"
"integrations/pi/skills" = "basic_memory/data/pi/package/skills"
"integrations/pi/skill-references" = "basic_memory/data/pi/package/skill-references"
"integrations/pi/package.json" = "basic_memory/data/pi/package/package.json"
"integrations/pi/package-lock.json" = "basic_memory/data/pi/package/package-lock.json"
"integrations/pi/README.md" = "basic_memory/data/pi/package/README.md"
"integrations/pi/SKILLS.md" = "basic_memory/data/pi/package/SKILLS.md"
"integrations/pi/LICENSE" = "basic_memory/data/pi/package/LICENSE"
[tool.uv-dynamic-versioning]
vcs = "git"
style = "pep440"
bump = true
fallback-version = "0.0.0"
[tool.ty.environment]
# Mirrors pytest's pythonpath, which puts tests/ on the import path for shared helpers.
extra-paths = ["tests"]
[tool.ty.rules]
all = "error"
[tool.coverage.run]
# Nothing in basic_memory uses gevent. Declaring it forced the slower C tracer on
# every coverage run and doubled test time; sysmon (COVERAGE_CORE) needs it gone.
concurrency = ["thread"]
parallel = true
source = ["basic_memory"]
[tool.coverage.report]
# A ratchet, not the goal: CI's combined coverage over all four suites measured
# 96.34% when it started enforcing it (97.16% locally on macOS). Raise it as gaps
# close; the target is 100%.
fail_under = 96
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]
# Exclude specific modules that are difficult to test comprehensively
omit = [
"*/external_auth_provider.py", # External HTTP calls to OAuth providers
"*/supabase_auth_provider.py", # External HTTP calls to Supabase APIs
"*/watch_service.py", # File system watching - complex integration testing
"*/background_sync.py", # Background processes
"*/cli/**", # CLI is an interactive wrapper; core logic is covered via API/MCP/service tests
"*/db.py", # Backend/runtime-dependent (sqlite/postgres/windows tuning); validated via integration tests
"*/services/initialization.py", # Startup orchestration + background tasks (watchers); exercised indirectly in entrypoints
"*/sync/sync_service.py", # Heavy filesystem/db integration; covered by integration suite, not enforced in unit coverage
"*/services/migration_service.py", # Complex migration scenarios
]