[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "keep-skill"
version = "0.114.1"
description = "Reflective memory - remember and search documents by meaning"
readme = "README.md"
requires-python = ">=3.11,<3.14"
license = {text = "MIT"}
authors = [{name = "Hugh Pyle"}]
keywords = ["semantic-memory", "vector-search", "embeddings", "chromadb", "agents", "langchain", "langgraph"]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
    "Topic :: Text Processing",
    "Topic :: Software Development :: Libraries",
]

dependencies = [
    "chromadb>=0.4",
    "pyyaml>=6.0",
    "requests>=2.33",
    "typer>=0.9",
    "tomli-w>=1.0",
    # Lightweight API SDKs (~2MB total, no heavy deps)
    "openai>=1.0",
    "anthropic>=0.40.0",
    "google-genai>=1.0.0",
    "mistralai>=1.0",
    # Document extraction
    "pyjwt>=2.12.0",
    "pypdf>=6.9.2",  # CVE-2026-33699: infinite loop in non-strict mode
    "pypdfium2>=4.0",
    "beautifulsoup4>=4.9",
    "python-docx>=1.0",
    "python-pptx>=1.0",
    # Audio metadata
    "tinytag>=2.2.1",
    # Image metadata
    "Pillow>=10.0",
    # Remote API client
    "httpx>=0.27",
    # MCP stdio server
    "mcp>=1.0",
    # CEL predicates for state-doc rules
    "common-expression-language>=0.5",
    # Interactive CLI prompts (setup wizard)
    "questionary>=2.0",
]

[project.urls]
Homepage = "https://keepnotes.ai"
Documentation = "https://docs.keepnotes.ai/guides/"
Repository = "https://github.com/keepnotes-ai/keep"

[project.optional-dependencies]
# Local models (macOS Apple Silicon optimized, ~500MB with PyTorch)
local = [
    "mlx>=0.10; platform_system == 'Darwin' and platform_machine == 'arm64'",
    "mlx-lm>=0.10; platform_system == 'Darwin' and platform_machine == 'arm64'",
    "sentence-transformers>=2.2",
]
# Media description (Apple Silicon vision + audio models)
media = [
    "mlx-vlm>=0.1; platform_system == 'Darwin' and platform_machine == 'arm64'",
    "mlx-whisper>=0.1; platform_system == 'Darwin' and platform_machine == 'arm64'",
]
# LangChain integration (LangGraph BaseStore, Retriever, Tools, Middleware)
langchain = [
    "langchain-core>=1.0.0,<2.0.0",
    "langgraph-checkpoint>=2.1.0,<5.0.0",
]
# Development
dev = [
    "pytest>=7.0",
    "pytest-cov>=4.0",
    "pytest-asyncio>=0.24",
    "ruff>=0.9",
]

[project.scripts]
keep = "keep.thin_cli:main"

[tool.hatch.build.targets.wheel.hooks.custom]
path = "hatch_build.py"

[tool.hatch.build.targets.wheel]
packages = ["keep"]

[tool.hatch.build.targets.wheel.force-include]
"SKILL.md" = "keep/SKILL.md"
"README.md" = "keep/README.md"
"docs" = "keep/docs"

[tool.hatch.build.targets.sdist]
include = [
    "/keep",
    "/docs",
    "/SKILL.md",
    "/README.md",
    "/LICENSE",
]

[tool.ruff]
target-version = "py311"
line-length = 120

[tool.ruff.lint]
select = ["D"]
ignore = [
    "D100",  # Missing docstring in public module
    "D102",  # Missing docstring in public method
    "D103",  # Missing docstring in public function
    "D104",  # Missing docstring in public package
    "D105",  # Missing docstring in magic method
    "D107",  # Missing docstring in __init__
]

[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.pytest.ini_options]
testpaths = ["tests"]
norecursedirs = [".venv", "dist", ".git"]
addopts = "-m 'not slow'"
markers = [
    "slow: marks tests as slow (require ML models)",
    "e2e: marks tests as end-to-end (require real providers)",
]
filterwarnings = [
    "ignore::DeprecationWarning:importlib._bootstrap",
]

[tool.coverage.run]
source = ["keep"]
omit = [
    "keep/providers/mlx*.py",
    "keep/providers/whisper*.py",
    "keep/setup_wizard.py",
    "keep/data/*",
]

[tool.coverage.report]
show_missing = true
skip_covered = true
exclude_lines = [
    "pragma: no cover",
    "if TYPE_CHECKING:",
    "if __name__",
    "raise NotImplementedError",
]
