[build-system]
requires = ["hatchling>=1.25,<2.0"]
build-backend = "hatchling.build"

[project]
name = "clawstu"
version = "0.2.0"
description = "Stuart — a personal learning agent that grows with the student."
readme = "README.md"
requires-python = ">=3.11"
license = { file = "LICENSE" }
authors = [
    { name = "SirhanMacx" },
]
keywords = ["education", "ai", "learning", "adaptive", "zpd", "open-source"]
classifiers = [
    "Development Status :: 2 - Pre-Alpha",
    "Framework :: FastAPI",
    "Intended Audience :: Education",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Topic :: Education",
    "Topic :: Education :: Computer Aided Instruction (CAI)",
]

dependencies = [
    "anthropic>=0.25,<1.0",
    "apscheduler>=3.10,<4.0",
    "fastapi>=0.110,<1.0",
    "httpx>=0.27,<1.0",
    "numpy>=1.26,<3.0",
    "onnxruntime>=1.20,<3.0",
    "openai>=1.20,<2.0",
    "pydantic>=2.6,<3.0",
    "rich>=13.7,<15.0",
    "tokenizers>=0.15,<1.0",
    "typer>=0.12,<1.0",
    "uvicorn[standard]>=0.29,<1.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=8.0",
    "pytest-asyncio>=0.23",
    "pytest-cov>=5.0",
    "ruff>=0.4",
    "mypy>=1.10",
]

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

[project.scripts]
clawstu = "clawstu.cli:main"

[tool.pytest.ini_options]
minversion = "8.0"
addopts = "-ra --strict-markers --strict-config"
testpaths = ["tests"]
asyncio_mode = "auto"
filterwarnings = [
    "error",
    "ignore::DeprecationWarning:pydantic.*",
]

[tool.coverage.run]
branch = true
source = ["clawstu"]

[tool.coverage.report]
show_missing = true
skip_covered = false
fail_under = 80

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

[tool.ruff.lint]
select = ["E", "F", "W", "I", "UP", "B", "SIM", "RUF"]
# B008: FastAPI uses `Depends()` in default args as a documented pattern.
# E501: long lines are fine; we have a 100-char limit but prose in strings
# sometimes runs longer and that's acceptable.
# UP042: `class X(str, Enum)` is the pattern that interops cleanly with
# Pydantic/JSON across Python versions; StrEnum's `str()` behavior differs
# and we prefer the portable form for now.
ignore = ["E501", "B008", "UP042"]

[tool.mypy]
python_version = "3.11"
strict = true
warn_unreachable = true
warn_unused_ignores = true
disallow_untyped_defs = true

# APScheduler ships without a py.typed marker, so mypy cannot resolve
# its public API. Rather than sprinkling `# type: ignore[import-untyped]`
# across clawstu.scheduler.runner, silence it at the module level. The
# runner exposes a tight typed shell (SchedulerRunner) around the
# untyped dependency, which is where the real type discipline lives.
[[tool.mypy.overrides]]
module = "apscheduler.*"
ignore_missing_imports = true
