[project] name = "code-context-engine" version = "0.4.26" description = "Save 94% on AI coding tokens. Index your codebase, agents search instead of reading files. Works with Claude Code, Cursor, Codex, Copilot, Gemini CLI. Local MCP server, free, open source." readme = {file = "README.md", content-type = "text/markdown"} license = "MIT" authors = [ {name = "Fazle Elahee", email = "felahee@gmail.com"}, {name = "Raj", email = "rajkumar.sakti@gmail.com"}, ] keywords = ["claude-code", "codex", "copilot", "cursor", "gemini-cli", "save-tokens", "token-savings", "mcp-server", "code-indexing", "reduce-ai-costs", "ai-coding", "vector-search"] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Libraries", ] requires-python = ">=3.11" dependencies = [ "click>=8.1", "pyyaml>=6.0", "sqlite-vec>=0.1.6", "numpy>=1.24", # Cap below 0.26: the tree-sitter 0.26 core changed the Node/Point ABI, # and the tree-sitter-* grammar wheels below are still built against the # 0.25.x ABI. Mixing 0.26 core with 0.25 grammars corrupts memory when # reading Node.start_point/end_point, crashing `cce init` with # SIGSEGV/SIGBUS (issues #113, #114). `uv tool install` resolves this # fresh from PyPI (ignoring uv.lock), so the cap must live here. Lift it # only when all grammar packages ship 0.26-ABI releases. "tree-sitter>=0.22,<0.26", "tree-sitter-python>=0.21", "tree-sitter-javascript>=0.21", "tree-sitter-typescript>=0.21", "tree-sitter-php>=0.23", "tree-sitter-go>=0.23", "tree-sitter-rust>=0.23", "tree-sitter-java>=0.23", "tree-sitter-c-sharp>=0.23", "watchdog>=4.0", # Upper bound is deliberate. mcp 2.0.0 removed the decorator registration API # (Server.list_tools / Server.call_tool), so an unbounded "mcp>=1.0" resolves to 2.x # and ContextEngineMCP raises AttributeError in __init__ — the MCP server does not # start at all. See #147. Lift this once the server is ported to the 2.x API. "mcp>=1.0,<2", "httpx>=0.27", "fastapi>=0.110", "uvicorn>=0.29", # Memory-capture loopback HTTP server — `cce serve` won't start the # capture path without it. Was originally optional; promoted to core # because hooks are core to the memory feature. "aiohttp>=3.9", "psutil>=5.9", ] [project.urls] Homepage = "https://github.com/elara-labs/code-context-engine" Repository = "https://github.com/elara-labs/code-context-engine" Issues = "https://github.com/elara-labs/code-context-engine/issues" [project.optional-dependencies] dev = [ "pytest>=8.0", "pytest-asyncio>=0.23", "pytest-aiohttp>=1.0", "pytest-cov>=5.0", "pytest-xdist>=3.5", "ruff>=0.13", ] http = [] # back-compat: aiohttp is now a core dependency # Local on-device embedding via fastembed (ONNX). ~172 MB install # footprint; needed only if you don't have Ollama running. Without # this extra, CCE auto-detects Ollama at localhost:11434 and uses # nomic-embed-text via /api/embed. local = ["fastembed>=0.4"] [project.scripts] cce = "context_engine.cli:main" code-context-engine = "context_engine.cli:main" cce-savings = "context_engine.cli:savings_shortcut" [build-system] requires = ["setuptools>=68.0"] build-backend = "setuptools.build_meta" [tool.setuptools.packages.find] where = ["src"] [tool.setuptools.package-data] "context_engine.data" = ["*.md"] [tool.pytest.ini_options] testpaths = ["tests"] asyncio_mode = "auto" pythonpath = ["src"] # Run tests in parallel via pytest-xdist. Capped at 4 workers to match # Embedder._PARALLEL and keep peak memory under ~1.5 GB (each worker # process loads its own ~60 MB ONNX model). Override with `-n auto` (use # all logical cores) or `-n 1` (serial) on the command line. # # `--dist=loadgroup` keeps tests marked `@pytest.mark.xdist_group(name=…)` # inside the same worker. We use this to pin all Ollama-hitting tests to # one worker — phi3:mini serves requests serially under load and the 30s # per-call timeout would otherwise race when 4 workers fire summarize() # at once. addopts = "-n 4 --dist=loadgroup" [dependency-groups] dev = [ "pytest>=9.0.3", "pytest-asyncio>=1.3.0", "pytest-aiohttp>=1.0", "pytest-xdist>=3.5", "ruff>=0.13", ] [tool.ruff] line-length = 100 target-version = "py311" extend-exclude = ["dist", "build", ".venv"] [tool.ruff.lint] # Default ruleset — pycodestyle errors (E) + pyflakes (F). Conservative # starting point; can be expanded later (I/imports, B/bugbear, UP/pyupgrade) # once the team is comfortable with the baseline. Selected rules are the # ones that catch real bugs (unused imports, undefined names, redefined # symbols) rather than stylistic preferences. select = ["E", "F", "W"] # E501 (line-too-long) is enforced via `line-length` above; default is 88 # but we use 100 to match the existing codebase. Ignore a few rules that # are noisy in async/test code: ignore = [ "E501", # line-too-long: handled by formatter, not all old code wrapped "E402", # module-import-not-at-top: legitimate inside conditional imports "E741", # ambiguous-variable-name (l/I/O): one-off in third-party-style code ] [tool.ruff.lint.per-file-ignores] # Tests import fixtures and helpers that look unused but trigger collection. "tests/**" = ["F811"] # __init__.py files are allowed to re-export (those imports look unused but # are part of the public surface of the package). "**/__init__.py" = ["F401"]