[build-system] requires = ["setuptools==83.0.0", "wheel==0.47.0"] build-backend = "setuptools.build_meta" [project] name = "solstone" version = "1.0.17" description = "Navigate Life Intelligently" readme = "README.md" requires-python = ">=3.12" license = {text = "AGPL-3.0-only"} authors = [ {name = "Jer Miller", email = "jer@solpbc.org"} ] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: GNU Affero General Public License v3", "Operating System :: POSIX :: Linux", "Operating System :: MacOS :: MacOS X", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Multimedia :: Sound/Audio :: Analysis", "Topic :: Multimedia :: Graphics :: Capture :: Screen Capture", "Topic :: Scientific/Engineering :: Artificial Intelligence", ] keywords = ["audio", "transcription", "screenshot", "multimodal", "ai", "gemini"] dependencies = [ # The thin `sol` access surface only. `pip install solstone` (the default) # is a thin client that talks to a journal — it carries NO provider SDKs, # no AI/media/ML runtime, no Flask. Install a journal host through # `pip install solstone-journal` or `pip install solstone-journal-cuda`. # # This partition is the boundary the access-surface import-clean guard # (scripts/check_access_imports_clean.py) and the extras-consistency lint # (scripts/check_extras_consistency.py) enforce. Adding a dependency here # must keep the `sol` access commands import-clean — do not add anything the # journal host needs; that belongs in [journal-host] below. "setproctitle", "typer", "requests", # Link tunnel client (`sol link serve`/`join`, think/link/): TLS 1.3 in # memory-BIO mode over an opaque WebSocket; pyOpenSSL supplies the # handshake-time verify callback that stdlib ssl can't express. "cryptography>=42,<47", "pyOpenSSL>=24.0", # argon2id for the journal-mark work factor (think/link/mark.py). "argon2-cffi", "websockets>=13.0", "psutil", "userpath>=1.9.2,<2", "solstone-core==1.0.17; sys_platform == 'linux' and platform_machine == 'x86_64'", "solstone-core==1.0.17; sys_platform == 'linux' and platform_machine == 'aarch64'", "solstone-core==1.0.17; sys_platform == 'darwin' and platform_machine == 'arm64'", "solstone-core-unsupported-platform==1.0.17; (sys_platform != 'linux' and sys_platform != 'darwin') or (sys_platform == 'linux' and platform_machine != 'x86_64' and platform_machine != 'aarch64') or (sys_platform == 'darwin' and platform_machine != 'arm64')", ] [project.optional-dependencies] # --------------------------------------------------------------------------- # Install menu. `pip install solstone` is the thin access client above. # The journal is now its own package: # # pip install solstone-journal # the journal (CPU) # pip install solstone-journal-cuda # the journal on NVIDIA CUDA # # [journal] and [journal-cuda] are retired tombstones that fail loudly and point # old installs at the new leaf packages. They no longer install the journal. # # [journal-host], [pdf-import], [pdf-export], and [pdf] remain internal # building blocks. The leaf packages compose [journal-host] with either the CPU # ONNX runtime or the NVIDIA CUDA runtime; [pdf] is a convenience composite of # [pdf-import] and [pdf-export], while the split extras back focused feature hints. # # Base solstone owns the public POSIX launchers. The platform-native # `solstone-core` executable is installed as the launcher sibling. Install exactly # one journal leaf; the CPU and GPU ONNX wheels own the same `onnxruntime/` # import dir and clobber each other. # --------------------------------------------------------------------------- pdf-import = [ "pypdfium2>=5.11,<6", "Pillow>=11.0.0", ] pdf-export = [ "weasyprint>=60.0", ] pdf = [ "solstone[pdf-import]", "solstone[pdf-export]", ] # The full journal-host stack EXCEPT the ONNX runtime package (which is the # CPU-vs-CUDA choice made by the solstone-journal leaf packages). Not a # user-facing extra — always pulled in by a leaf package. journal-host = [ "solstone-journal-models==1.0.0", "python-dotenv", "pyhpke==0.6.4", "Flask[async]", "Markdown", "mistune", "python-frontmatter", "packaging", "Pillow>=11.0.0", "numpy", "tokenizers>=0.20", "av", "openai>=1.2.0", "openhands-sdk==1.27.*", # OpenHands leaves LiteLLM broad. Keep production on the exact version # exercised by uv.lock: 1.92.0 started importing FastAPI from the core # completion path even though neither package declares that proxy extra. "litellm==1.86.1", # Pinned to >=1.27.1: that release reverts the Gemini prompt-cache markers # (upstream PR #3586 / issue #3585). Emitting cache_control on Gemini froze # its cache at the static prefix and disabled Google's implicit caching # (~6-14x cost); keep implicit caching available for exact Gemini defaults # and any explicit gemini-2.5/3 pin. # openhands-sdk pulls lmnr's OpenTelemetry beta stack. Pin the matching line # so pip does not mix newer 1.42/0.63 packages with lmnr's 0.60b1 # semantic-conventions pin. "opentelemetry-api==1.39.1", "opentelemetry-sdk==1.39.1", "opentelemetry-exporter-otlp-proto-grpc==1.39.1", "opentelemetry-exporter-otlp-proto-http==1.39.1", "opentelemetry-instrumentation==0.60b1", "opentelemetry-instrumentation-threading==0.60b1", "opentelemetry-semantic-conventions==0.60b1", # 0.6.2 = validated continuous-batching-fix baseline; <0.7 pins it # so on-device builds don't float past the soak-validated server-wedge fix. "mlx-vlm>=0.6.2,<0.7; sys_platform == 'darwin' and platform_machine == 'arm64'", "mlx>=0.31.2,<1; sys_platform == 'darwin' and platform_machine == 'arm64'", "huggingface-hub>=0.24", "httpx", "h2", "jsonschema>=4.26,<5", "genai-prices", "icalendar", "blessed>=1.20.0", "tzlocal", "python-slugify", "rapidfuzz", # Audio processing "soundfile", "kaldi-native-fbank>=1.22", # solstone/apps/speakers/{owner,discovery}.py use sklearn.cluster.HDBSCAN. # Previously pulled transitively via resemblyzer; now a direct dep. "scikit-learn>=1.3", # Media processing "opencv-python-headless", # PDF folds into the journal host ("choose journal, get it all"). Referenced # via the building-block extra so the per-feature hints stay in sync. "solstone[pdf]", ] # TOMBSTONE. The journal moved out of the root distribution into its own # packages. `solstone[journal]` and the `solstone-journal-host` shim are retired; # this extra now pins a build-fails-by-design tombstone so every old spelling # fails loudly at install time instead of silently thin-installing. Install the # journal via: # pip install solstone-journal # the journal (CPU) # pip install solstone-journal-cuda # the journal on NVIDIA CUDA # The pin is STATIC (never rewritten per release); render_packaging.py --check # and check_extras_consistency.py verify it stays exactly this. journal = ["solstone-journal-host==0.7.0"] # TOMBSTONE (see [journal] above). Retired — same loud-failure tombstone pin. # Install `solstone-journal-cuda` for the NVIDIA CUDA runtime. journal-cuda = ["solstone-journal-host==0.7.0"] [project.urls] Homepage = "https://github.com/solpbc/solstone-journal" Repository = "https://github.com/solpbc/solstone-journal" Documentation = "https://github.com/solpbc/solstone-journal/blob/main/README.md" "Bug Tracker" = "https://github.com/solpbc/solstone-journal/issues" [tool.setuptools] # Raw root launchers are script-file payloads, not console entry points, so # uv-tool exports the root-owned public commands while dependency-owned core # scripts stay inside the tool environment. script-files = [ "scripts/root-launchers/sol", "scripts/root-launchers/solstone", ] # Package data is included wholesale via MANIFEST.in (`graft solstone`) plus the # include-package-data flag below. We deliberately do NOT hand-maintain per-subdir # package-data globs: that curated list repeatedly dropped data files added in new # subdirectories — the installed wheel would silently omit e.g. # solstone/think/contract/layout.json while source-tree `make ci` stayed green, # hard-500ing observer ingest. Including every non-.py file under solstone/ is the # correct default here: the long tail of .json/.md/.html/.schema.json data files # is intentionally shipped. If a file lives under solstone/ at build time, it # ships. New data file → no pyproject edit required. include-package-data = true [tool.setuptools.packages.find] include = ["solstone*"] exclude = ["*.tests", "*.tests.*"] [tool.setuptools.cmdclass] build_py = "build_hooks.BuildPyWithoutTests" [tool.uv] # Tombstone dependencies are build-fails-by-design distributions that must NOT # resolve during workspace development. This override prunes them from workspace # resolution: the marker `python_version < '3.12'` contradicts requires-python = # ">=3.12", so uv drops the requirement entirely (uv lock succeeds; no tombstone # node lands in uv.lock). [tool.uv] is never published, so end-user wheel # METADATA still carries the tombstone pins and fails loudly at install time. override-dependencies = [ "solstone-journal-host==0.7.0; python_version < '3.12'", "solstone-core-unsupported-platform==1.0.17; python_version < '3.12'", ] [tool.uv.workspace] members = ["packages/solstone-journal", "packages/solstone-journal-cuda", "packages/solstone-journal-models", "packages/solstone-core", "packages/solstone-core-speakers-analyze"] [tool.uv.sources] solstone-journal = {workspace = true} solstone-journal-cuda = {workspace = true} solstone-journal-models = {workspace = true} solstone-core = {workspace = true} solstone-core-speakers-analyze = {workspace = true} # Development tools configuration [tool.ruff] target-version = "py312" exclude = [".venv", "scratch", "logs", "build", "dist"] [tool.ruff.lint] select = ["F", "E", "W", "I"] ignore = ["E501", "E203", "E402"] [tool.pytest.ini_options] addopts = "--import-mode=importlib" asyncio_mode = "strict" testpaths = ["tests", "solstone/apps"] python_files = ["test_*.py"] python_classes = ["Test*"] python_functions = ["test_*"] markers = [ "integration: exercises real local processes, builds, or persisted index contracts outside unit CI", "performance: asserts a wall-clock performance floor and is opt-in on an idle host", "real_local_backend_probe: opts out of the deterministic bundled local backend probe monkeypatch", "xdist_group: marks tests to run in the same xdist worker group", ] timeout = 15 tmp_path_retention_policy = "none" filterwarnings = [ # Third-party deprecation warnings (Python 3.14+) "ignore:codecs.open.* is deprecated:DeprecationWarning", "ignore:.*_UnionGenericAlias.* is deprecated:DeprecationWarning", "ignore:.*DefaultEventLoopPolicy.* is deprecated:DeprecationWarning", ] [dependency-groups] dev = [ "freezegun", "onnx", "pytest", "pytest-asyncio", "pytest-cov", "pytest-timeout", "pytest-xdist", "ruff", "schemathesis", "setuptools", # Test-only: encrypted PDF fixture construction in tests/pdf_worker_fixtures.py. "pypdf>=4.0.0", ] journal-cpu = ["solstone-journal"] journal-cuda = ["solstone-journal-cuda"]