[project] name = "everos" version = "1.0.0" description = "EverOS — local-first markdown memory framework for AI agents and user chats; lightweight, dev-friendly, small-team" license = {text = "Apache-2.0"} readme = "README.md" requires-python = ">=3.12" authors = [ {name = "EverMind AI"}, ] keywords = ["memory", "ai-agent", "markdown", "lancedb", "rag", "everos"] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.12", "Topic :: Scientific/Engineering :: Artificial Intelligence", ] dependencies = [ # Core data validation & config "pydantic>=2.7.1", "pydantic-settings>=2.0.0", "python-dotenv>=1.0.1", # Storage stack (md-first three-piece set) "lancedb>=0.13.0", # Vector + BM25 + scalar filter (Arrow-based) "aiosqlite>=0.20.0", # Async SQLite driver (used by SA async engine) "sqlmodel>=0.0.22", # ORM (Pydantic + SQLAlchemy 2.0 async) "alembic>=1.13.0", # SQLite schema migrations "greenlet>=3.0", # Required by SQLAlchemy async # LLM & embedding (one provider per file pattern) "openai>=1.0.0", # Markdown / file system "PyYAML>=6.0", # YAML frontmatter parsing "watchdog>=4.0.0", # Cross-platform file system events (cascade daemon) # Web framework (entrypoints/api) "fastapi>=0.104.0", "uvicorn[standard]>=0.24.0", # Observability (core/observability) "structlog>=24.0.0", "prometheus-client>=0.20.0", # CLI "typer>=0.12.0", # Tokenization (BM25 Chinese support) "jieba==0.42.1", # OME (Offline Memory Evolution) async scheduler & file I/O "apscheduler>=3.10.4,<4.0", # async strategy scheduler chassis "portalocker>=2.8.2", # cross-platform file lock for single-engine guard "watchfiles>=0.21.0", # native fs watcher for config hot reload "anyio>=4.0", # Async file I/O (anyio.Path, to_thread.run_sync) for the markdown layer # Algorithm library (everalgo monorepo, published on PyPI). "everalgo-core==0.2.0", "everalgo-boundary==0.2.0", "everalgo-user-memory==0.2.0", "everalgo-agent-memory==0.2.0", "everalgo-rank==0.3.0", ] [project.optional-dependencies] multimodal = ["everalgo-parser[svg]>=0.1.0"] # [svg] bundles cairosvg → SVG works by default [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["src/everos"] # ``env.template`` lives at src/everos/templates/env.template and is # auto-included via ``packages``. ``everos init`` reads it through # ``importlib.resources``. No force-include needed. # sdist uses an include-whitelist (not exclude) so we don't accidentally ship # things like CLAUDE.md, .claude/, CI configs, or IDE settings. New top-level # files default to NOT-shipped — you have to opt them in here. # # exclude is kept as belt-and-suspenders for build artefacts that CI may # generate inside the project tree (e.g. UV_CACHE_DIR=.uv-cache). [tool.hatch.build.targets.sdist] include = [ "/src", "/tests", "/data", "/docs", "/pyproject.toml", "/uv.lock", "/README.md", "/QUICKSTART.md", "/CHANGELOG.md", "/CONTRIBUTING.md", "/CODE_OF_CONDUCT.md", "/SECURITY.md", "/ACKNOWLEDGMENTS.md", "/CITATION.md", "/LICENSE", "/NOTICE", "/config.example.toml", ] exclude = [".uv-cache", ".venv"] [project.scripts] everos = "everos.entrypoints.cli.main:app" # ─────────────────────────────────────────────────────────────────────────────── # Tooling # ─────────────────────────────────────────────────────────────────────────────── [tool.ruff] line-length = 88 target-version = "py312" extend-exclude = ["src_old"] [tool.ruff.lint] select = ["E", "F", "I", "N", "UP", "B", "SIM", "ASYNC"] [tool.ruff.lint.per-file-ignores] # LoCoMo benchmark embeds LLM prompts (ANSWER_PROMPT / JUDGE_*_PROMPT) and # verbose argparse help strings as multi-line string literals. Line breaks # would change what the LLM actually sees or noise the --help output, so # E501 is silenced for this file only. "tests/test_locomo.py" = ["E501"] [tool.pytest.ini_options] testpaths = ["tests"] python_files = ["test_*.py"] python_functions = ["test_*"] asyncio_mode = "auto" addopts = "-v --tb=short -m 'not slow and not live_llm'" markers = [ "slow: runs that take >=10s (regardless of dependency); CI default excludes these. Run with `pytest -m slow`.", "live_llm: requires real LLM / embedder / reranker credentials from .env; burns tokens. CI default excludes. Run with `pytest -m live_llm`.", ] [tool.coverage.run] source = ["src/everos"] branch = true omit = ["**/__init__.py"] [tool.importlinter] root_packages = ["everos"] [[tool.importlinter.contracts]] name = "Layered architecture" type = "layers" layers = [ "everos.entrypoints", "everos.service", "everos.memory", "everos.infra", ] [[tool.importlinter.contracts]] name = "Subpackage internals are private" type = "forbidden" source_modules = ["everos.service", "everos.memory", "everos.entrypoints"] # `**` matches any descendant (writer.py, reader.py, sub.foo.bar, ...). # Public API must be reached via the subpackage `__init__.py`. forbidden_modules = [ "everos.infra.persistence.markdown.**", "everos.infra.persistence.lancedb.**", "everos.infra.persistence.sqlite.**", ] # `forbidden` contracts run a *transitive closure* — any path from a # source module to a forbidden module fails the check, even when the # source only imports the subpackage top-level. The whitelist below # carves out **intra-subpackage wiring**: each storage subpackage's # own ``__init__.py`` imports its own ``tables`` / ``repos`` / manager # children to assemble the public API surface that outer layers reach. # These edges are normal Python package wiring, *not* a privacy # breach — without these ignores, even a legitimate # ``from everos.infra.persistence.sqlite import X`` would be punished # because the transitive scan walks one hop further into the package. # # Direct imports from outer layers into a subpackage internal module # (e.g. ``from everos.infra.persistence.sqlite.tables import X`` written # in ``service`` or ``entrypoints``) remain blocked — that edge is not # in this whitelist. ignore_imports = [ "everos.infra.persistence.sqlite -> everos.infra.persistence.sqlite.tables", "everos.infra.persistence.sqlite -> everos.infra.persistence.sqlite.repos", "everos.infra.persistence.sqlite -> everos.infra.persistence.sqlite.sqlite_manager", "everos.infra.persistence.lancedb -> everos.infra.persistence.lancedb.tables", "everos.infra.persistence.lancedb -> everos.infra.persistence.lancedb.repos", "everos.infra.persistence.lancedb -> everos.infra.persistence.lancedb.lancedb_manager", "everos.infra.persistence.markdown -> everos.infra.persistence.markdown.mds", "everos.infra.persistence.markdown -> everos.infra.persistence.markdown.writers", "everos.infra.persistence.markdown -> everos.infra.persistence.markdown.readers", ] [[tool.importlinter.contracts]] name = "OME does not depend on memory/service/entrypoints or sibling infra subpackages" type = "forbidden" source_modules = ["everos.infra.ome"] forbidden_modules = [ "everos.infra.persistence", "everos.memory", "everos.service", "everos.entrypoints", ] [dependency-groups] dev = [ "ruff>=0.8.0", "pytest>=8.4.0", "pytest-asyncio>=1.1.0", "pytest-cov>=6.0.0", "pytest-rerunfailures>=15.0", "import-linter>=2.0", "pre-commit>=4.0.0", "ipdb>=0.13.13", "pyinstrument>=5.0.0", ]