rememble 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. rememble-0.1.1/.gitignore +12 -0
  2. rememble-0.1.1/Dockerfile +15 -0
  3. rememble-0.1.1/Makefile +40 -0
  4. rememble-0.1.1/PKG-INFO +124 -0
  5. rememble-0.1.1/README.md +103 -0
  6. rememble-0.1.1/docker-compose.yml +6 -0
  7. rememble-0.1.1/pyproject.toml +56 -0
  8. rememble-0.1.1/rememble/__init__.py +5 -0
  9. rememble-0.1.1/rememble/config.py +72 -0
  10. rememble-0.1.1/rememble/db.py +315 -0
  11. rememble-0.1.1/rememble/embeddings/__init__.py +6 -0
  12. rememble-0.1.1/rememble/embeddings/base.py +24 -0
  13. rememble-0.1.1/rememble/embeddings/compat.py +50 -0
  14. rememble-0.1.1/rememble/embeddings/factory.py +77 -0
  15. rememble-0.1.1/rememble/embeddings/local.py +61 -0
  16. rememble-0.1.1/rememble/embeddings/ollama.py +49 -0
  17. rememble-0.1.1/rememble/ingest/__init__.py +1 -0
  18. rememble-0.1.1/rememble/ingest/chunker.py +53 -0
  19. rememble-0.1.1/rememble/models.py +88 -0
  20. rememble-0.1.1/rememble/rag/__init__.py +1 -0
  21. rememble-0.1.1/rememble/rag/context.py +130 -0
  22. rememble-0.1.1/rememble/search/__init__.py +1 -0
  23. rememble-0.1.1/rememble/search/fusion.py +142 -0
  24. rememble-0.1.1/rememble/search/graph.py +147 -0
  25. rememble-0.1.1/rememble/search/temporal.py +33 -0
  26. rememble-0.1.1/rememble/search/text.py +77 -0
  27. rememble-0.1.1/rememble/search/vector.py +49 -0
  28. rememble-0.1.1/rememble/server.py +462 -0
  29. rememble-0.1.1/rememble/version.py +10 -0
  30. rememble-0.1.1/tests/__init__.py +0 -0
  31. rememble-0.1.1/tests/conftest.py +67 -0
  32. rememble-0.1.1/tests/test_db.py +117 -0
  33. rememble-0.1.1/tests/test_embeddings.py +187 -0
  34. rememble-0.1.1/tests/test_ingest.py +47 -0
  35. rememble-0.1.1/tests/test_rag.py +53 -0
  36. rememble-0.1.1/tests/test_search.py +111 -0
  37. rememble-0.1.1/tests/test_server.py +290 -0
  38. rememble-0.1.1/uv.lock +2717 -0
@@ -0,0 +1,12 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ .pytest_cache/
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+ .ruff_cache/
9
+ plans/
10
+ CLAUDE.md
11
+ .envrc
12
+ .python-version
@@ -0,0 +1,15 @@
1
+ FROM python:3.12-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # Install uv for fast dependency resolution
6
+ COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
7
+
8
+ COPY pyproject.toml .
9
+ COPY src/ src/
10
+
11
+ RUN uv sync --no-dev --frozen 2>/dev/null || uv sync --no-dev
12
+
13
+ ENV REMEMBLE_DB_PATH=/data/memory.db
14
+
15
+ ENTRYPOINT ["uv", "run", "rememble"]
@@ -0,0 +1,40 @@
1
+ .PHONY: dev test lint fmt check bump publish release
2
+
3
+ BUMP ?= patch
4
+
5
+ dev: ## Install in development mode
6
+ uv sync --all-extras
7
+ @echo "✓ Development mode ready"
8
+
9
+ test: ## Run tests
10
+ uv run pytest -v
11
+
12
+ lint: ## Lint + type check
13
+ uv run ruff check rememble/ tests/
14
+ uv run basedpyright rememble/
15
+
16
+ fmt: ## Format + fix imports
17
+ uv run ruff format rememble/ tests/
18
+ uv run ruff check --fix rememble/ tests/
19
+
20
+ check: fmt lint test ## Format, lint, type check, test
21
+
22
+ bump: ## Bump version (BUMP=major|minor|patch)
23
+ uv version --bump $(BUMP)
24
+
25
+ publish: ## Build + publish to PyPI
26
+ rm -rf dist/
27
+ uv build
28
+ uv publish
29
+
30
+ release: check ## Full release: fmt, lint, test, bump, tag, push, publish
31
+ @if [ -n "$$(git status --porcelain)" ]; then echo "ERROR: dirty working tree" && exit 1; fi
32
+ uv version --bump $(BUMP)
33
+ $(eval VERSION := $(shell uv version --short))
34
+ git add pyproject.toml uv.lock
35
+ git commit -m "chore(release): v$(VERSION)"
36
+ git tag "v$(VERSION)"
37
+ git push && git push --tags
38
+ $(MAKE) publish
39
+
40
+ .DEFAULT_GOAL := dev
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: rememble
3
+ Version: 0.1.1
4
+ Summary: Local MCP memory server with hybrid search, knowledge graph, and RAG
5
+ Author-email: Nik Cubrilovic <git@nikcub.me>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.11
8
+ Requires-Dist: fastmcp>=2.0
9
+ Requires-Dist: httpx>=0.27
10
+ Requires-Dist: pydantic-settings>=2.0
11
+ Requires-Dist: pydantic>=2.0
12
+ Requires-Dist: sqlite-vec>=0.1.6
13
+ Requires-Dist: tiktoken>=0.8
14
+ Provides-Extra: all
15
+ Requires-Dist: onnxruntime>=1.19; extra == 'all'
16
+ Requires-Dist: sentence-transformers>=3.0; extra == 'all'
17
+ Provides-Extra: local
18
+ Requires-Dist: onnxruntime>=1.19; extra == 'local'
19
+ Requires-Dist: sentence-transformers>=3.0; extra == 'local'
20
+ Description-Content-Type: text/markdown
21
+
22
+ # Rememble
23
+
24
+ Local-first memory server with hybrid search, knowledge graph, and RAG context assembly.
25
+
26
+ SQLite + sqlite-vec + FTS5 backend. Works with any MCP client.
27
+
28
+ ## Features
29
+
30
+ - Hybrid search: BM25 + vector KNN + temporal scoring (RRF fusion)
31
+ - Knowledge graph: entities, observations, relations
32
+ - Token-budgeted RAG context assembly
33
+ - Multiple embedding providers: Ollama, local (sentence-transformers), OpenAI-compat
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ uv sync
39
+ ```
40
+
41
+ ## MCP Client Setup
42
+
43
+ ### Claude Code / Claude Desktop
44
+
45
+ ```json
46
+ {
47
+ "mcpServers": {
48
+ "rememble": {
49
+ "command": "uv",
50
+ "args": ["run", "--directory", "/path/to/Rememble", "rememble"]
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ ## Configuration
57
+
58
+ Config file: `~/.rememble/config.json` (auto-created on first run).
59
+
60
+ All fields can be overridden via env vars with `REMEMBLE_` prefix and `__` as nested delimiter.
61
+
62
+ | Env var | Default | Description |
63
+ |---------|---------|-------------|
64
+ | `REMEMBLE_DB_PATH` | `~/.rememble/memory.db` | SQLite database path |
65
+ | `REMEMBLE_EMBEDDING__PROVIDER` | `ollama` | `ollama` \| `local` \| `compat` |
66
+ | `REMEMBLE_EMBEDDING__MODEL` | `nomic-embed-text` | Model name for active provider |
67
+ | `REMEMBLE_EMBEDDING__DIMENSIONS` | `768` | Embedding dimensions |
68
+ | `REMEMBLE_EMBEDDING__OLLAMA_URL` | `http://localhost:11434` | Ollama base URL |
69
+ | `REMEMBLE_EMBEDDING__API_TYPE` | `openrouter` | Label for compat provider (logging only) |
70
+ | `REMEMBLE_EMBEDDING__API_ENDPOINT` | `https://openrouter.ai/api/v1` | OpenAI-compat base URL |
71
+ | `REMEMBLE_EMBEDDING__API_KEY` | — | API key (or set `OPENROUTER_API_KEY` / `OPENAI_API_KEY`) |
72
+
73
+ ## Embedding Providers
74
+
75
+ ### Ollama (default)
76
+ ```json
77
+ { "embedding": { "provider": "ollama", "model": "nomic-embed-text", "dimensions": 768 } }
78
+ ```
79
+
80
+ ### Local (sentence-transformers, no network)
81
+ ```bash
82
+ uv sync --extra local
83
+ ```
84
+ ```json
85
+ { "embedding": { "provider": "local" } }
86
+ ```
87
+
88
+ ### OpenAI-compat (OpenRouter, OpenAI, Cohere compat, etc.)
89
+
90
+ **OpenRouter:**
91
+ ```json
92
+ {
93
+ "embedding": {
94
+ "provider": "compat",
95
+ "api_type": "openrouter",
96
+ "api_endpoint": "https://openrouter.ai/api/v1",
97
+ "model": "openai/text-embedding-3-small",
98
+ "dimensions": 1536
99
+ }
100
+ }
101
+ ```
102
+
103
+ **Cohere via OpenAI compat API:**
104
+ ```json
105
+ {
106
+ "embedding": {
107
+ "provider": "compat",
108
+ "api_type": "cohere",
109
+ "api_endpoint": "https://api.cohere.com/compatibility/v1",
110
+ "model": "embed-english-light-v3.0",
111
+ "dimensions": 384
112
+ }
113
+ }
114
+ ```
115
+
116
+ Set `REMEMBLE_EMBEDDING__API_KEY` or `OPENROUTER_API_KEY` / `OPENAI_API_KEY` env var.
117
+
118
+ ## Development
119
+
120
+ ```bash
121
+ make dev # install deps
122
+ make test # run tests
123
+ make check # fmt + lint + test
124
+ ```
@@ -0,0 +1,103 @@
1
+ # Rememble
2
+
3
+ Local-first memory server with hybrid search, knowledge graph, and RAG context assembly.
4
+
5
+ SQLite + sqlite-vec + FTS5 backend. Works with any MCP client.
6
+
7
+ ## Features
8
+
9
+ - Hybrid search: BM25 + vector KNN + temporal scoring (RRF fusion)
10
+ - Knowledge graph: entities, observations, relations
11
+ - Token-budgeted RAG context assembly
12
+ - Multiple embedding providers: Ollama, local (sentence-transformers), OpenAI-compat
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ uv sync
18
+ ```
19
+
20
+ ## MCP Client Setup
21
+
22
+ ### Claude Code / Claude Desktop
23
+
24
+ ```json
25
+ {
26
+ "mcpServers": {
27
+ "rememble": {
28
+ "command": "uv",
29
+ "args": ["run", "--directory", "/path/to/Rememble", "rememble"]
30
+ }
31
+ }
32
+ }
33
+ ```
34
+
35
+ ## Configuration
36
+
37
+ Config file: `~/.rememble/config.json` (auto-created on first run).
38
+
39
+ All fields can be overridden via env vars with `REMEMBLE_` prefix and `__` as nested delimiter.
40
+
41
+ | Env var | Default | Description |
42
+ |---------|---------|-------------|
43
+ | `REMEMBLE_DB_PATH` | `~/.rememble/memory.db` | SQLite database path |
44
+ | `REMEMBLE_EMBEDDING__PROVIDER` | `ollama` | `ollama` \| `local` \| `compat` |
45
+ | `REMEMBLE_EMBEDDING__MODEL` | `nomic-embed-text` | Model name for active provider |
46
+ | `REMEMBLE_EMBEDDING__DIMENSIONS` | `768` | Embedding dimensions |
47
+ | `REMEMBLE_EMBEDDING__OLLAMA_URL` | `http://localhost:11434` | Ollama base URL |
48
+ | `REMEMBLE_EMBEDDING__API_TYPE` | `openrouter` | Label for compat provider (logging only) |
49
+ | `REMEMBLE_EMBEDDING__API_ENDPOINT` | `https://openrouter.ai/api/v1` | OpenAI-compat base URL |
50
+ | `REMEMBLE_EMBEDDING__API_KEY` | — | API key (or set `OPENROUTER_API_KEY` / `OPENAI_API_KEY`) |
51
+
52
+ ## Embedding Providers
53
+
54
+ ### Ollama (default)
55
+ ```json
56
+ { "embedding": { "provider": "ollama", "model": "nomic-embed-text", "dimensions": 768 } }
57
+ ```
58
+
59
+ ### Local (sentence-transformers, no network)
60
+ ```bash
61
+ uv sync --extra local
62
+ ```
63
+ ```json
64
+ { "embedding": { "provider": "local" } }
65
+ ```
66
+
67
+ ### OpenAI-compat (OpenRouter, OpenAI, Cohere compat, etc.)
68
+
69
+ **OpenRouter:**
70
+ ```json
71
+ {
72
+ "embedding": {
73
+ "provider": "compat",
74
+ "api_type": "openrouter",
75
+ "api_endpoint": "https://openrouter.ai/api/v1",
76
+ "model": "openai/text-embedding-3-small",
77
+ "dimensions": 1536
78
+ }
79
+ }
80
+ ```
81
+
82
+ **Cohere via OpenAI compat API:**
83
+ ```json
84
+ {
85
+ "embedding": {
86
+ "provider": "compat",
87
+ "api_type": "cohere",
88
+ "api_endpoint": "https://api.cohere.com/compatibility/v1",
89
+ "model": "embed-english-light-v3.0",
90
+ "dimensions": 384
91
+ }
92
+ }
93
+ ```
94
+
95
+ Set `REMEMBLE_EMBEDDING__API_KEY` or `OPENROUTER_API_KEY` / `OPENAI_API_KEY` env var.
96
+
97
+ ## Development
98
+
99
+ ```bash
100
+ make dev # install deps
101
+ make test # run tests
102
+ make check # fmt + lint + test
103
+ ```
@@ -0,0 +1,6 @@
1
+ services:
2
+ rememble:
3
+ build: .
4
+ stdin_open: true
5
+ volumes:
6
+ - ~/.rememble:/data
@@ -0,0 +1,56 @@
1
+ [project]
2
+ name = "rememble"
3
+ version = "0.1.1"
4
+ description = "Local MCP memory server with hybrid search, knowledge graph, and RAG"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ authors = [{ name = "Nik Cubrilovic", email = "git@nikcub.me" }]
8
+ requires-python = ">=3.11"
9
+ dependencies = [
10
+ "fastmcp>=2.0",
11
+ "sqlite-vec>=0.1.6",
12
+ "tiktoken>=0.8",
13
+ "pydantic>=2.0",
14
+ "pydantic-settings>=2.0",
15
+ "httpx>=0.27",
16
+ ]
17
+
18
+ [project.optional-dependencies]
19
+ local = ["sentence-transformers>=3.0", "onnxruntime>=1.19"]
20
+ all = ["rememble[local]"]
21
+
22
+ [project.scripts]
23
+ rememble = "rememble.server:main"
24
+
25
+ [build-system]
26
+ requires = ["hatchling"]
27
+ build-backend = "hatchling.build"
28
+
29
+ [tool.hatch.build.targets.wheel]
30
+ packages = ["rememble"]
31
+
32
+ [dependency-groups]
33
+ dev = [
34
+ "pytest>=8.0",
35
+ "pytest-asyncio>=0.24",
36
+ "basedpyright>=1.20",
37
+ "ruff>=0.8",
38
+ ]
39
+
40
+ [tool.ruff]
41
+ target-version = "py311"
42
+ line-length = 100
43
+
44
+ [tool.ruff.lint]
45
+ select = ["E", "F", "I", "UP", "B", "SIM"]
46
+
47
+ [tool.basedpyright]
48
+ pythonVersion = "3.11"
49
+ typeCheckingMode = "standard"
50
+ reportCallIssue = "warning"
51
+ venvPath = "."
52
+ venv = ".venv"
53
+
54
+ [tool.pytest.ini_options]
55
+ asyncio_mode = "auto"
56
+ testpaths = ["tests"]
@@ -0,0 +1,5 @@
1
+ """Rememble — local memory server with hybrid search and knowledge graph."""
2
+
3
+ from rememble.version import __version__
4
+
5
+ __all__ = ["__version__"]
@@ -0,0 +1,72 @@
1
+ """Config loading from ~/.rememble/config.json with env var overrides."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+ from typing import ClassVar, Literal
8
+
9
+ from pydantic import BaseModel, Field
10
+ from pydantic_settings import BaseSettings, SettingsConfigDict
11
+
12
+ CONFIG_DIR = Path.home() / ".rememble"
13
+ CONFIG_PATH = CONFIG_DIR / "config.json"
14
+
15
+
16
+ class EmbeddingConfig(BaseModel):
17
+ provider: str = "ollama"
18
+ model: str = "nomic-embed-text"
19
+ dimensions: int = 768
20
+ ollama_url: str = "http://localhost:11434"
21
+ # OpenAI-compat settings (provider="compat")
22
+ api_type: str = "openrouter" # label only: openai | openrouter | cohere | etc.
23
+ api_endpoint: str = "https://openrouter.ai/api/v1"
24
+ api_key: str | None = None
25
+ # Local settings
26
+ local_model: str = "sentence-transformers/all-MiniLM-L6-v2"
27
+ local_backend: Literal["torch", "onnx", "openvino"] = "onnx"
28
+
29
+
30
+ class SearchConfig(BaseModel):
31
+ default_limit: int = 10
32
+ rrf_k: int = 60
33
+ bm25_weight: float = 0.4
34
+ vector_weight: float = 0.5
35
+ temporal_weight: float = 0.1
36
+ recency_half_life_days: float = 7.0
37
+
38
+
39
+ class RAGConfig(BaseModel):
40
+ max_context_tokens: int = 1500
41
+ max_snippets: int = 24
42
+ snippet_max_tokens: int = 200
43
+ expansion_max_tokens: int = 600
44
+
45
+
46
+ class ChunkingConfig(BaseModel):
47
+ target_tokens: int = 400
48
+ overlap_tokens: int = 40
49
+
50
+
51
+ class RemembleConfig(BaseSettings):
52
+ model_config: ClassVar[SettingsConfigDict] = SettingsConfigDict(
53
+ env_prefix="REMEMBLE_",
54
+ env_nested_delimiter="__",
55
+ extra="ignore",
56
+ )
57
+ db_path: str = Field(default_factory=lambda: str(CONFIG_DIR / "memory.db"))
58
+ embedding: EmbeddingConfig = Field(default_factory=EmbeddingConfig)
59
+ search: SearchConfig = Field(default_factory=SearchConfig)
60
+ rag: RAGConfig = Field(default_factory=RAGConfig)
61
+ chunking: ChunkingConfig = Field(default_factory=ChunkingConfig)
62
+
63
+
64
+ def loadConfig() -> RemembleConfig:
65
+ """Load config from ~/.rememble/config.json with env var overrides."""
66
+ if CONFIG_PATH.exists():
67
+ raw = json.loads(CONFIG_PATH.read_text())
68
+ return RemembleConfig(**raw)
69
+ CONFIG_DIR.mkdir(parents=True, exist_ok=True)
70
+ config = RemembleConfig()
71
+ CONFIG_PATH.write_text(config.model_dump_json(indent=2))
72
+ return config