| [build-system] | |
| requires = ["hatchling"] | |
| build-backend = "hatchling.build" | |
| [project] | |
| name = "loosecanvas" | |
| version = "0.1.0" | |
| description = "Co-created understanding map: local LLM Γ Cytoscape.js" | |
| license = "MIT" | |
| authors = [{ name = "Joshua Sundance Bailey" }] | |
| requires-python = ">=3.13" | |
| dependencies = [ | |
| "fastapi>=0.115", | |
| "uvicorn[standard]>=0.41", | |
| "gradio>=5.0", | |
| "pydantic>=2.13", | |
| "networkx>=3.6", | |
| "httpx>=0.28", | |
| "PyYAML>=6.0", | |
| "markdown-it-py>=4.0", | |
| "aiofiles>=25.1", | |
| "python-multipart>=0.0.22", | |
| "sse-starlette>=3.3", | |
| "jinja2>=3.1", | |
| # M16: LangGraph turn state machine (routing + checkpointed conversation memory). | |
| "langgraph>=1.2", | |
| "langchain-core>=1.4", | |
| # Agent-forward turn loop: create_agent harness + middleware + ChatOpenAI driving | |
| # the local llama.cpp OpenAI-compatible endpoint (tool calling + token streaming). | |
| "langchain>=1.3", | |
| "langchain-openai>=1.3", | |
| "openai>=2.0", | |
| ] | |
| [project.optional-dependencies] | |
| dev = [ | |
| "pytest>=9.0", | |
| "pytest-asyncio>=1.3", | |
| "pytest-cov>=7.0", | |
| "mypy>=1.18", | |
| "types-PyYAML", | |
| "types-aiofiles", | |
| "pre-commit>=4.0", | |
| ] | |
| # M02 builds the `response_format` payload from the ScenePlan schema; the llama.cpp | |
| # server does JSON-Schema->grammar conversion internally, so no local grammar tooling | |
| # (llama-cpp-python / jsonref) is required. No `llm` optional group is needed. | |
| [tool.hatch.build.targets.wheel] | |
| packages = ["src/loosecanvas"] | |
| # ββ Ruff βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| [tool.ruff] | |
| line-length = 120 | |
| target-version = "py313" | |
| src = ["src/loosecanvas", "tests"] | |
| [tool.ruff.lint] | |
| select = [ | |
| "E", # pycodestyle errors | |
| "W", # pycodestyle warnings | |
| "F", # pyflakes | |
| "I", # isort | |
| "N", # pep8-naming | |
| "UP", # pyupgrade | |
| "S", # bandit security | |
| "B", # bugbear | |
| "A", # flake8-builtins | |
| "C4", # flake8-comprehensions | |
| "DTZ", # flake8-datetimez (naive datetime usage) | |
| "T20", # flake8-print | |
| "SIM", # flake8-simplify | |
| "ERA", # flake8-eradicate (commented-out code) | |
| ] | |
| ignore = [ | |
| "S101", # assert in tests is fine | |
| ] | |
| [tool.ruff.lint.per-file-ignores] | |
| "scripts/**" = ["T201", "S310"] | |
| "archive/**" = ["T201", "S310"] # frozen PoC utility scripts (e.g. split_plan.py) | |
| "src/loosecanvas/llm_probe.py" = ["S310"] | |
| # Module holds a long natural-language SYSTEM_PROMPT literal; prose lines exceed 120. | |
| "src/loosecanvas/agent_harness.py" = ["E501"] | |
| "tests/**" = ["S101", "T20"] | |
| # ββ Mypy ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| [tool.mypy] | |
| python_version = "3.13" | |
| strict = true | |
| warn_return_any = true | |
| warn_unused_configs = true | |
| warn_unused_ignores = true | |
| mypy_path = "src" | |
| explicit_package_bases = true | |
| # The M19 custom component is an external, untyped Gradio package β installed at | |
| # runtime (Dockerfile) and in local dev, but NOT in CI's `uv sync` env. Treat its | |
| # import as Any so `mypy src` passes regardless of whether it is installed. | |
| [[tool.mypy.overrides]] | |
| module = ["gradio_cytoscapecanvas.*"] | |
| ignore_missing_imports = true | |
| # ββ Pytest ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| [tool.pytest.ini_options] | |
| asyncio_mode = "auto" | |
| testpaths = ["tests"] | |
| pythonpath = ["src"] | |
| addopts = "--tb=short -q --cov=src --cov-report=term-missing --cov-fail-under=70" | |
| # Imports: from loosecanvas.contracts import Node (not: from contracts import Node) | |
| # ββ Coverage ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| [tool.coverage.run] | |
| source = ["src"] | |
| omit = ["tests/*"] | |
| branch = true | |
| [tool.coverage.report] | |
| show_missing = true | |
| skip_covered = false | |
| [tool.pyright] | |
| # Point pyright (incl. the standalone pyright-lsp plugin Claude Code spawns) at the | |
| # project venv so venv-only imports resolve instead of emitting false reportMissingImports. | |
| # VS Code's python.defaultInterpreterPath only configures Pylance, not this pyright. | |
| venvPath = "." | |
| venv = ".venv" | |
| extraPaths = ["src"] | |