# SPDX-License-Identifier: AGPL-3.0-or-later # Commercial license available # © Concepts 1996–2026 Miroslav Šotek. All rights reserved. # © Code 2020–2026 Miroslav Šotek. All rights reserved. # ORCID: 0009-0009-3560-0851 # Contact: www.anulum.li | protoscience@anulum.li # SYNAPSE_CHANNEL — project metadata, tooling, and packaging configuration [build-system] requires = ["setuptools>=68", "wheel"] build-backend = "setuptools.build_meta" [project] name = "synapse-channel" version = "0.99.26" description = "Local-first coordination bus for AI agents across one repository or a whole ecosystem: work claims, presence, chat, a shared plan, and resource sharing over a WebSocket hub" readme = "README.md" requires-python = ">=3.10" license = "AGPL-3.0-or-later" license-files = ["LICENSE", "NOTICE.md", "LICENSES/*"] authors = [ { name = "Miroslav Šotek", email = "protoscience@anulum.li" }, ] keywords = ["multi-agent", "coordination", "websocket", "task-claims", "local-first"] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Topic :: Communications :: Chat", "Topic :: Software Development :: Libraries", ] dependencies = [ "websockets>=13.0", ] [project.optional-dependencies] dev = [ "ruff>=0.15.9", "mypy>=1.20.0", "pytest>=9.0.3", "pytest-asyncio>=0.23", "pytest-cov>=5.0", # The installed-console-scripts gate builds a real wheel with # ``python -m build --wheel --no-isolation`` and force-installs it into a fresh # venv, so the build frontend plus the declared setuptools/wheel backend must be # present in the test environment (``--no-isolation`` does not provision them). "build>=1.5.0", "setuptools>=68", "setuptools-scm[toml]>=3.4.3", "wheel>=0.43", "pkgconfig>=1.5.5", "packaging>=26.2", "prometheus-client>=0.20", "hypothesis>=6.100", "bandit>=1.7", "pip-audit>=2.7", "pre-commit>=4.0", "reuse>=6.0", "tomli>=2.4.1; python_version < '3.11'", "mcp==1.28.1", "grpcio>=1.62.0", "sqlcipher3-binary==0.6.0; sys_platform == 'linux'", "cryptography>=42.0", "python-pkcs11>=0.9", "wasmtime>=14.0.0", "opentelemetry-sdk>=1.43.0", "opentelemetry-exporter-otlp-proto-http>=1.43.0", "tree-sitter>=0.26.0", "tree-sitter-python>=0.25.0", "tree-sitter-javascript>=0.25.0", "tree-sitter-typescript>=0.23.2", "tree-sitter-rust>=0.24.2", "tree-sitter-go>=0.25.0", ] # NB: tpm2-pytss (the [tpm2] extra) is deliberately NOT in dev. It is sdist-only and its build # needs the TSS2 system headers (libtss2-dev), so putting it in the hash-locked requirements-dev.txt # would break every CI job that installs those requirements without the system libraries (docs, type, # lint). The test job installs it separately after apt-installing libtss2-dev + swtpm. benchmark = [ "tiktoken>=0.7", ] wasm = [ "wasmtime>=14.0.0", ] otel = [ "opentelemetry-sdk>=1.43.0", "opentelemetry-exporter-otlp-proto-http>=1.43.0", ] mcp = [ "mcp==1.28.1", "cryptography>=42.0", ] a2a-grpc = [ "grpcio>=1.62.0", ] semantic = [ "tree-sitter>=0.26.0", "tree-sitter-python>=0.25.0", "tree-sitter-javascript>=0.25.0", "tree-sitter-typescript>=0.23.2", "tree-sitter-rust>=0.24.2", "tree-sitter-go>=0.25.0", ] encryption = [ "cryptography>=42.0", ] sqlcipher = [ # Page-level encryption for live hub --db (EventStore). Verified at # https://pypi.org/pypi/sqlcipher3-binary/0.6.0/ — manylinux cp312 wheel # sha256:c8a7076a18b4f6fc9b580b0f24aa526d6a47605b1e3e6491ee3e9f2977940d8e "sqlcipher3-binary==0.6.0", ] pkcs11 = [ "python-pkcs11>=0.9", ] tpm2 = [ "tpm2-pytss>=2.3", ] cloud-hsm = [ "boto3>=1.34", ] all = [ "wasmtime>=14.0.0", "opentelemetry-sdk>=1.43.0", "opentelemetry-exporter-otlp-proto-http>=1.43.0", "mcp==1.28.1", "cryptography>=42.0", "sqlcipher3-binary==0.6.0", "python-pkcs11>=0.9", "tpm2-pytss>=2.3", "boto3>=1.34", "tree-sitter>=0.26.0", "tree-sitter-python>=0.25.0", "tree-sitter-javascript>=0.25.0", "tree-sitter-typescript>=0.23.2", "tree-sitter-rust>=0.24.2", "tree-sitter-go>=0.25.0", ] docs = [ "mkdocs-material>=9.5", "mkdocstrings[python]>=0.26", ] [project.scripts] synapse = "synapse_channel.cli:main" synapse-channel = "synapse_channel.cli_mcp:main" syn = "synapse_channel.ergonomics:main" syn-name = "synapse_channel.ergonomics:alias_name" syn-wait = "synapse_channel.ergonomics:alias_arm" syn-say = "synapse_channel.ergonomics:alias_say" syn-ask = "synapse_channel.ergonomics:alias_ask" syn-inbox = "synapse_channel.ergonomics:alias_inbox" syn-board = "synapse_channel.ergonomics:alias_board" syn-reap = "synapse_channel.ergonomics:alias_reap" syn-locks = "synapse_channel.ergonomics:alias_locks" syn-ack = "synapse_channel.ergonomics:alias_ack" syn-commit = "synapse_channel.ergonomics:alias_commit" [project.urls] Homepage = "https://www.anulum.li" Repository = "https://github.com/anulum/synapse-channel" Issues = "https://github.com/anulum/synapse-channel/issues" Changelog = "https://github.com/anulum/synapse-channel/blob/main/CHANGELOG.md" Documentation = "https://anulum.github.io/synapse-channel" Funding = "https://www.anulum.li/licensing" [tool.setuptools.packages.find] where = ["src"] [tool.setuptools.package-data] synapse_channel = [ "py.typed", "schemas/*.json", "dashboard_assets/*.css", "dashboard_assets/*.js", "dashboard_assets/fonts/*.md", "dashboard_assets/fonts/*.woff2", ] [tool.ruff] line-length = 100 target-version = "py310" src = ["src", "tests", "benchmarks"] extend-exclude = ["legacy"] [tool.ruff.lint] select = ["E", "F", "I", "B", "UP", "D"] ignore = ["D203", "D212"] [tool.ruff.lint.pydocstyle] convention = "numpy" [tool.ruff.lint.per-file-ignores] # Tests favour descriptive function names over docstrings on every case. "tests/*" = ["D"] # The header generator must select the matplotlib backend before importing pyplot. "docs/assets/*" = ["E402"] # Dev tooling scripts are not part of the documented API surface. "tools/*" = ["D"] [tool.mypy] strict = true python_version = "3.10" mypy_path = "src" files = ["src/synapse_channel", "tests", "benchmarks", "tools", "examples"] exclude = ["legacy/"] warn_unused_configs = true warn_return_any = true [[tool.mypy.overrides]] module = [ "websockets.*", "tiktoken", "tomli", "pysqlcipher3", "pysqlcipher3.*", "sqlcipher3", "sqlcipher3.*", "wasmtime", "wasmtime.*", "yaml", "tpm2_pytss", "tpm2_pytss.*", "boto3", "boto3.*", ] ignore_missing_imports = true [tool.pytest.ini_options] testpaths = ["tests"] addopts = "-q --tb=short --strict-markers" asyncio_mode = "auto" markers = [ "docs_contract: documentation/design-contract guards (not a runtime e2e journey)", "real_hub: exercises a live or subprocess hub runtime path", ] [tool.coverage.run] source = ["synapse_channel"] branch = true [tool.coverage.report] show_missing = true fail_under = 98 precision = 2 exclude_lines = [ "pragma: no cover", "if __name__ == .__main__.:", "if TYPE_CHECKING:", "raise NotImplementedError", "@(typing\\.)?overload", ] [tool.bandit] exclude_dirs = ["tests", "benchmarks", "legacy", ".venv"] skips = ["B101"]