A 5e storytelling engine with an LLM DM
1[project]
2name = "storied"
3version = "0.1.0"
4description = "An AI-powered text adventure RPG with persistent worldbuilding"
5readme = "README.md"
6requires-python = ">=3.12"
7license = "MIT"
8authors = [
9 { name = "Chris Guidry" }
10]
11
12dependencies = [
13 "argcomplete>=3.0",
14 "fastembed>=0.4",
15 "fastmcp>=3.2",
16 "httpx>=0.27",
17 "pydantic-monty>=0.0.9",
18 "pymupdf>=1.24",
19 "pymupdf4llm>=0.0.17",
20 "pysqlite3-binary>=0.5",
21 "pyyaml>=6.0",
22 "rich>=13.0",
23 "sqlite-vec>=0.1",
24 "uncalled-for>=0.1",
25]
26
27[project.scripts]
28storied = "storied.cli:main"
29
30[project.optional-dependencies]
31dev = [
32 "pytest>=8.0",
33 "pytest-cov>=4.0",
34 "mypy>=1.0",
35 "ruff>=0.1",
36]
37
38[build-system]
39requires = ["hatchling"]
40build-backend = "hatchling.build"
41
42[tool.hatch.build.targets.wheel]
43packages = ["src/storied"]
44
45[tool.pytest.ini_options]
46testpaths = ["tests"]
47pythonpath = ["src"]
48addopts = [
49 "-n", "4",
50 "--cov=src/storied",
51 "--cov=tests",
52 "--cov-report=term-missing:skip-covered",
53 "--cov-branch",
54 # Target: 100%. Floor: 96% (the current reality on included code).
55 # Raise the floor as coverage improves; never lower it without a
56 # specific reason that's worth writing down.
57 "--cov-fail-under=96",
58 "-m", "not slow",
59]
60markers = ["slow: slow tests that build real search indices"]
61
62[tool.mypy]
63python_version = "3.12"
64strict = true
65
66[tool.ruff]
67target-version = "py312"
68line-length = 88
69
70[tool.ruff.lint]
71select = ["E", "F", "I", "UP", "B", "SIM", "PT", "RUF"]
72# B008 fires on the FastMCP + uncalled_for dependency-injection idiom
73# (`root: Path = StorageRoot()` etc). Those aren't mutable defaults —
74# they're DI markers resolved at call time. Suppressing project-wide
75# so real B008 regressions would still surface elsewhere.
76#
77# RUF001/002/003 flag ambiguous Unicode (em dashes, curly quotes, ×).
78# These are intentional throughout the project's prose, prompts, and
79# comments — the house style uses em dashes.
80ignore = ["B008", "RUF001", "RUF002", "RUF003"]
81
82[tool.codespell]
83# Skip the SRD content (5e creature/feature names trip the spell-check)
84# and uv.lock. Allow specific intentional terms elsewhere: phonological
85# diphthongs, partial streaming-test fragments, and valid spelling
86# variants.
87skip = "rules/**,uv.lock"
88ignore-words-list = "ue,ie,hel,wit,unparseable"
89
90[tool.pyright]
91include = ["src", "tests"]
92# Strict surfaces ~1300 errors here, mostly reportUnknownX from
93# dict/yaml/dynamic-prompt code that pre-dates a strict typing pass.
94# Basic catches the real bugs without requiring every locals to be
95# explicitly typed. Tighten as the codebase becomes more annotated.
96typeCheckingMode = "basic"
97venvPath = "."
98venv = ".venv"
99
100[tool.coverage.run]
101source = ["src/storied"]
102branch = true
103omit = ["src/storied/cli.py", "src/storied/srd/*"]
104
105[dependency-groups]
106dev = [
107 "mypy>=1.19.1",
108 "pyright>=1.1.408",
109 "pytest>=9.0.2",
110 "pytest-cov>=7.0.0",
111 "pytest-xdist>=3.8.0",
112 "ruff>=0.14.10",
113]