# Tenets Project Configuration
[project]
name = "tenets"
version = "0.9.3"
description = "MCP server for AI coding assistants — intelligent code context via Model Context Protocol"
authors = [{name = "Tenets Team", email = "team@tenets.dev"}]
readme = {file = "README.md", content-type = "text/markdown"}
license = {text = "MIT"}
requires-python = ">=3.9"
keywords = ["mcp", "model-context-protocol", "ai", "llm", "code-analysis", "prompt-engineering", "developer-tools", "context-management", "cursor", "claude", "ai-coding-assistant"]
# PyPI classifiers
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Quality Assurance",
"Topic :: Software Development :: Code Generators",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
]
# Core dependencies
dependencies = [
"click>=8.1.0",
"typer>=0.9.0",
"rich>=13.0.0",
"pydantic>=2.0.0",
"pydantic-settings>=2.0.0",
"httpx>=0.25.0",
"gitpython>=3.1.0",
"pathspec>=0.11.0",
"chardet>=5.0.0",
"aiofiles>=23.0.0",
"tqdm>=4.65.0",
"psutil>=5.9.0",
"PyYAML>=6.0",
"numpy>=1.24.0", # For TF-IDF and ranking calculations
]
[project.urls]
Homepage = "https://github.com/jddunn/tenets"
Documentation = "https://tenets.dev/docs"
Repository = "https://github.com/jddunn/tenets"
Issues = "https://github.com/jddunn/tenets/issues"
Changelog = "https://github.com/jddunn/tenets/blob/main/CHANGELOG.md"
[project.scripts]
tenets = "tenets.cli.app:app"
tenets-mcp = "tenets.mcp.server:main"
[project.optional-dependencies]
# MCP Server (Model Context Protocol for AI assistants)
mcp = [
"mcp[cli]>=1.0.0",
"sse-starlette>=1.6.0",
"uvicorn>=0.23.0",
"scikit-learn>=1.3.0", # Required for default TextRank summarization
"nltk>=3.8.0", # Required for TextRank
]
# Visualization (graphs, charts)
viz = [
"networkx>=3.0",
"matplotlib>=3.7.0",
"graphviz>=0.20.0",
"plotly>=5.0.0",
"pydot>=1.4.0",
]
# Extra keyword extraction algorithms (optional - core already works fine)
light = [
"rake-nltk>=1.0.6",
"yake>=0.4.8",
"scikit-learn>=1.3.0",
"textstat>=0.7.3",
"nltk>=3.8.0",
]
# Deep learning for semantic search (2GB+ models)
ml = [
"torch>=2.0.0",
"transformers>=4.30.0",
"sentence-transformers>=2.2.0",
"tiktoken>=0.5.0",
"faiss-cpu>=1.7.4",
"openai>=1.0.0",
"anthropic>=0.25.0",
"litellm>=1.0.0",
"huggingface-hub>=0.19.0",
]
# (duplicate viz block removed; merged into the single viz list above)
# Web interface
web = [
"fastapi>=0.100.0",
"uvicorn[standard]>=0.23.0",
"websockets>=11.0",
"jinja2>=3.1.0",
"python-multipart>=0.0.6",
"sse-starlette>=1.6.0",
]
# Database and caching
db = [
"alembic>=1.12.0",
"sqlalchemy>=2.0.0",
"redis>=5.0.0",
"diskcache>=5.6.0", # For disk-based caching
]
# Development dependencies
dev = [
"pytest>=7.4.0",
"pytest-asyncio>=0.21.0",
"pytest-cov>=4.1.0",
"pytest-mock>=3.12.0",
"pytest-timeout>=2.2.0",
"pytest-xdist>=3.3.0",
"hypothesis>=6.82.0",
"faker>=19.0.0",
"freezegun>=1.2.0",
"coverage>=7.3.0",
"coverage-badge>=1.1.0",
"black>=23.0.0",
"isort>=5.12.0",
"ruff>=0.1.0",
"mypy>=1.5.0",
"autoflake>=2.2.0",
"bandit[toml]>=1.7.5",
"safety>=2.3.0",
"pre-commit>=3.4.0",
"mkdocs>=1.5.0",
# Optional: Imaging extras for Material social cards (cairosvg, pillow, etc.)
# Note: Rendering social cards needs native Cairo. Skip locally on Windows
# and enable only in CI or Linux if desired.
"mkdocs-material[imaging]>=9.5.0",
"mkdocs-git-revision-date-localized-plugin>=1.2.0",
"mkdocs-git-authors-plugin>=0.7.0",
"mkdocs-awesome-pages-plugin>=2.9.0",
"mkdocs-section-index>=0.3.0",
"mkdocs-macros-plugin>=0.9.0",
"mkdocs-mermaid2-plugin>=1.1.0",
"mkdocs-jupyter>=0.24.0",
"mkdocs-gen-files>=0.5.0",
"mkdocs-literate-nav>=0.6.0",
"mkdocstrings[python]>=0.24.0",
"mkdocs-autorefs>=1.0.0",
"mkdocs-minify-plugin>=0.8.0",
"mike>=2.0.0",
"build>=1.0.0",
"twine>=4.0.0",
"wheel>=0.41.0",
"commitizen>=3.12.0",
"pyinstaller>=6.0.0",
"pip-tools>=7.3.0",
]
# Test dependencies
test = [
"pytest>=7.4.0",
"pytest-asyncio>=0.21.0",
"pytest-cov>=4.1.0",
"pytest-mock>=3.12.0",
"pytest-timeout>=2.2.0",
"pytest-xdist>=3.3.0",
"hypothesis>=6.92.0",
"responses>=0.24.0",
"faker>=20.0.0",
# Include tiktoken so tokenization tests aren't skipped in core test matrix
"tiktoken>=0.5.0",
]
# Documentation dependencies
docs = [
"mkdocs>=1.5.0",
# Optional: Imaging extras for Material social cards (cairosvg, pillow, etc.)
# Requires native Cairo; safe to omit for local builds.
"mkdocs-material[imaging]>=9.5.0",
"mkdocstrings[python]>=0.23.0",
"mkdocs-minify-plugin>=0.7.0",
"pymdown-extensions>=10.0",
"mkdocs-gen-files>=0.5.0",
"mkdocs-awesome-pages-plugin>=2.9.0",
"mkdocs-literate-nav>=0.6.0",
"mkdocs-section-index>=0.3.0",
"mkdocs-git-revision-date-localized-plugin>=1.2.0",
"mkdocs-redirects>=1.2.0",
"mike>=2.0.0"
]
# All features
all = [
"tenets[light,ml,viz,web,db,mcp]",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build]
include = [
"tenets/**/*.py",
"tenets/**/*.json",
"tenets/**/*.yaml",
"tenets/**/*.yml",
"tenets/**/*.toml",
"tenets/**/*.html",
"tenets/**/*.css",
"tenets/**/*.js",
"tenets/**/*.txt", # Include stopwords.txt
]
exclude = [
"tests",
"docs",
"*.pyc",
"__pycache__",
]
[tool.black]
line-length = 100
target-version = ['py39']
include = '\.pyi?$'
extend-exclude = '''
/(
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| build
| dist
| __pycache__
)/
'''
[tool.isort]
profile = "black"
line_length = 100
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true
skip_glob = ["*/migrations/*", "*/venv/*"]
[tool.ruff]
line-length = 100
target-version = "py39"
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".hg",
".mypy_cache",
".nox",
".pants.d",
".ruff_cache",
".svn",
".tox",
".venv",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"venv",
]
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
"ARG", # flake8-unused-arguments
"SIM", # flake8-simplify
"TCH", # flake8-type-checking
"RUF", # ruff-specific rules
"PTH", # flake8-use-pathlib
"ERA", # eradicate
"PD", # pandas-vet
"PGH", # pygrep-hooks
"PL", # pylint
"TRY", # tryceratops
]
ignore = [
"E501", # line too long (handled by black)
"B008", # do not perform function calls in argument defaults
"B905", # zip() without an explicit strict= parameter
"PLR0913", # too many arguments to function call
"TRY003", # Avoid specifying long messages outside the exception class
"UP035", # deprecated typing imports (if you want to keep Python 3.9 compat)
"UP036", # version block considered outdated
]
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401", "F403"]
"tests/*" = ["ARG", "S101", "PLR2004"]
[tool.mypy]
python_version = "3.9"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true
strict_concatenate = true
plugins = ["pydantic.mypy"]
[[tool.mypy.overrides]]
module = [
"yake.*",
"sentence_transformers.*",
"tiktoken.*",
"transformers.*",
"faiss.*",
"nltk.*",
"networkx.*",
"plotly.*",
"matplotlib.*",
"graphviz.*",
]
ignore_missing_imports = true
[tool.pytest.ini_options]
minversion = "7.0"
addopts = [
"-ra",
"-q",
"--strict-markers",
"--cov=tenets",
"--cov-branch",
"--cov-report=term-missing",
"--cov-report=xml",
"--cov-report=html",
"--durations=10",
]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
norecursedirs = [
"venv",
".venv",
"Lib",
"lib",
"Scripts",
"bin",
"Include",
"include",
"site-packages",
"build",
"dist",
".git",
".hg",
".mypy_cache",
".pytest_cache",
]
markers = [
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
"integration: marks tests as integration tests",
"unit: marks tests as unit tests",
"requires_git: marks tests that require git",
"requires_ml: marks tests that require ML dependencies",
"requires_viz: marks tests that require visualization dependencies",
"cli: CLI command tests",
"smoke: Quick smoke tests for CI",
]
filterwarnings = [
"ignore::DeprecationWarning",
"ignore::PendingDeprecationWarning",
"ignore::ResourceWarning:coverage",
"ignore::ResourceWarning:_pytest",
"ignore::ResourceWarning:sqlite3",
"ignore::pytest.PytestUnraisableExceptionWarning",
]
[tool.coverage.run]
source = ["tenets"]
branch = true
parallel = true
concurrency = ["thread"]
sigterm = true
omit = [
"*/tests/*",
"*/test_*.py",
"*/__main__.py",
"*/cli/app.py",
# Optional features (users may not install)
"*/viz/*",
# Language analyzers (boilerplate, 18K lines)
"*/core/analysis/implementations/*_analyzer.py",
# Infrastructure utilities
"*/utils/external_sources.py",
"*/utils/multiprocessing.py",
"*/utils/timing.py",
]
[tool.coverage.report]
precision = 2
show_missing = true
skip_covered = false
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if TYPE_CHECKING:",
"raise AssertionError",
"raise NotImplementedError",
"if __name__ == .__main__.:",
"@abstractmethod",
]
[tool.commitizen]
name = "cz_conventional_commits"
version = "0.3.2"
tag_format = "v$version"
version_files = [
"tenets/__init__.py:__version__",
"pyproject.toml:version",
]
update_changelog_on_bump = true
major_version_zero = true
changelog_file = "CHANGELOG.md"
changelog_incremental = true
changelog_start_rev = "v0.1.0"
[tool.commitizen.customize]
bump_pattern = "^(feat|fix|perf|refactor|BREAKING)"
[tool.commitizen.customize.bump_map]
"BREAKING CHANGE" = "MAJOR"
"BREAKING" = "MAJOR"
"feat" = "MINOR"
"fix" = "PATCH"
"perf" = "PATCH"
"refactor" = "PATCH"
[tool.bandit]
exclude_dirs = ["tests", "venv", ".venv", "build", "dist"]
severity = "medium" # Only report medium and high severity issues
[tool.pydocstyle]
convention = "google"
match-dir = "^(?!tests|venv|build|dist).*"
add-ignore = ["D100", "D104"]