[project] name = "pmb-ai" version = "1.2.3" description = "PMB (Personal Memory Brain) - local-first persistent memory for AI coding agents (MCP server, fully offline, no API keys)" readme = "README.md" license = {text = "Apache-2.0"} requires-python = ">=3.11" authors = [{name = "PMB contributors"}] keywords = [ "mcp", "memory", "ai-agent", "claude-code", "codex", "cursor", "rag", "vector-search", "local-first", "bm25", "sqlite", "lancedb", ] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Libraries", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Database", ] dependencies = [ "fastmcp>=3.0", "sentence-transformers>=4.0", "lancedb>=0.30", "rank-bm25>=0.2", "numpy>=2.0", "typer>=0.15", "rich>=14.0", "pyyaml>=6.0", # `pmb connect codex` writes Codex's TOML config; stdlib `tomllib` # only reads, so we need this external writer. "tomli-w>=1.0", ] [project.optional-dependencies] tui = [ "textual>=8.0", ] dev = [ "pytest>=8.0", "pytest-asyncio>=0.24", "pytest-cov>=5.0", "hypothesis>=6.100", "ruff>=0.8", "textual>=8.0", ] consolidate = [ "anthropic>=0.40", ] fastembed = [ "fastembed>=0.4", ] crypto = [ # Encrypted workspace bundles (`pmb workspace export/import`). "cryptography>=42.0", ] all = [ "anthropic>=0.40", "fastembed>=0.4", "textual>=8.0", "cryptography>=42.0", ] [project.urls] Homepage = "https://github.com/oleksiijko/pmb" Documentation = "https://github.com/oleksiijko/pmb#readme" Repository = "https://github.com/oleksiijko/pmb" Issues = "https://github.com/oleksiijko/pmb/issues" Changelog = "https://github.com/oleksiijko/pmb/blob/main/CHANGELOG.md" [project.scripts] pmb = "pmb.cli:app" pmb-ai = "pmb.cli:app" # alias: the PyPI/npm package is `pmb-ai`, so `pmb-ai ...` works too pmb-mcp = "pmb.mcp.server:main" pmb-chat = "pmb.agent_wrapper.__main__:main" pmb-hook = "pmb.hookclient.__main__:main" [build-system] requires = ["setuptools>=68"] build-backend = "setuptools.build_meta" [tool.setuptools.packages.find] where = ["src"] [tool.setuptools.package-data] pmb = ["py.typed", "dashboard/static/*", "lang/packs/*.yaml"] [tool.ruff] line-length = 100 target-version = "py311" [tool.ruff.lint] select = ["E", "F", "I", "B", "UP"] # E501 line length is handled by the editor, not the gate. The rest are # deliberate idioms in this codebase that a blocking gate should not fight: # E402 — intentional lazy / conditional imports (keeps the hook path light) # E701/E702 — one-line guards (`if x: return`) and grouped imports in CLI code # B008 — typer.Option(...) / Argument(...) in defaults is the framework idiom # B904 — re-raising without `from` inside broad except is fine for our errlog # B905 — zip() without strict= predates 3.10 floors in a few hot loops # B007 — unused loop vars in graph walks are intentional (named for clarity) # E741 — a few single-letter names (l, I) in vendored-style math code ignore = [ "E501", "E402", "E701", "E702", "B008", "B904", "B905", "B007", "E741", ] [tool.ruff.lint.per-file-ignores] # scripts/ are throwaway benchmarks/dev tools — not shipped, not import-clean. "scripts/**" = ["F", "E", "B", "UP", "I"] # Tests routinely bind a name for the SIDE EFFECT of recording a fixture event # (the returned ulid is intentionally unused), e.g. `decoy = record_fact(...)`. # F841 there is noise, not a bug. "tests/**" = ["F841"] [tool.pytest.ini_options] testpaths = ["tests"] asyncio_mode = "auto" markers = [ "quarantined: load-flaky test — runs in a separate non-blocking CI job. MUST carry a one-line root-cause note next to the marker; should be retired once the harness is fixed (real waits, isolated engines).", "perf: latency / throughput smoke — excluded on memory-constrained runners.", "property: hypothesis property-based test.", "eval: memory-quality recall regression gate (top-1/top-3 floors, real deterministic embedder).", "platform_sensitive: numerically/timing platform-dependent (embedder float-variance, runner-load timing). Gates on the Linux reference runner + coverage job; the CI matrix skips it on Windows/macOS so cross-platform noise can't redden the build. MUST carry a one-line root-cause note next to the marker.", ]