agentmemdb 0.1.0__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 (46) hide show
  1. agentmemdb-0.1.0/CHANGELOG.md +24 -0
  2. agentmemdb-0.1.0/CONTRIBUTING.md +72 -0
  3. agentmemdb-0.1.0/LICENSE +21 -0
  4. agentmemdb-0.1.0/MANIFEST.in +6 -0
  5. agentmemdb-0.1.0/PKG-INFO +163 -0
  6. agentmemdb-0.1.0/README.md +129 -0
  7. agentmemdb-0.1.0/SECURITY.md +23 -0
  8. agentmemdb-0.1.0/docs/README.md +11 -0
  9. agentmemdb-0.1.0/docs/architecture.md +105 -0
  10. agentmemdb-0.1.0/docs/assets/logo-wordmark-dark.svg +35 -0
  11. agentmemdb-0.1.0/docs/assets/logo-wordmark-light.svg +35 -0
  12. agentmemdb-0.1.0/docs/assets/logo.svg +30 -0
  13. agentmemdb-0.1.0/docs/configuration.md +77 -0
  14. agentmemdb-0.1.0/docs/examples.md +218 -0
  15. agentmemdb-0.1.0/docs/getting-started.md +126 -0
  16. agentmemdb-0.1.0/docs/tools.md +169 -0
  17. agentmemdb-0.1.0/examples/config.json +11 -0
  18. agentmemdb-0.1.0/examples/memory-policy.md +33 -0
  19. agentmemdb-0.1.0/pyproject.toml +91 -0
  20. agentmemdb-0.1.0/setup.cfg +4 -0
  21. agentmemdb-0.1.0/src/agentmemdb/__init__.py +5 -0
  22. agentmemdb-0.1.0/src/agentmemdb/__main__.py +3 -0
  23. agentmemdb-0.1.0/src/agentmemdb/cli.py +54 -0
  24. agentmemdb-0.1.0/src/agentmemdb/config.py +92 -0
  25. agentmemdb-0.1.0/src/agentmemdb/icon.svg +30 -0
  26. agentmemdb-0.1.0/src/agentmemdb/models.py +93 -0
  27. agentmemdb-0.1.0/src/agentmemdb/py.typed +0 -0
  28. agentmemdb-0.1.0/src/agentmemdb/search.py +156 -0
  29. agentmemdb-0.1.0/src/agentmemdb/server.py +618 -0
  30. agentmemdb-0.1.0/src/agentmemdb/storage.py +136 -0
  31. agentmemdb-0.1.0/src/agentmemdb.egg-info/PKG-INFO +163 -0
  32. agentmemdb-0.1.0/src/agentmemdb.egg-info/SOURCES.txt +44 -0
  33. agentmemdb-0.1.0/src/agentmemdb.egg-info/dependency_links.txt +1 -0
  34. agentmemdb-0.1.0/src/agentmemdb.egg-info/entry_points.txt +2 -0
  35. agentmemdb-0.1.0/src/agentmemdb.egg-info/requires.txt +1 -0
  36. agentmemdb-0.1.0/src/agentmemdb.egg-info/top_level.txt +1 -0
  37. agentmemdb-0.1.0/tests/__init__.py +0 -0
  38. agentmemdb-0.1.0/tests/conftest.py +68 -0
  39. agentmemdb-0.1.0/tests/helpers.py +20 -0
  40. agentmemdb-0.1.0/tests/test_cli.py +59 -0
  41. agentmemdb-0.1.0/tests/test_config.py +87 -0
  42. agentmemdb-0.1.0/tests/test_e2e.py +111 -0
  43. agentmemdb-0.1.0/tests/test_package.py +21 -0
  44. agentmemdb-0.1.0/tests/test_search.py +46 -0
  45. agentmemdb-0.1.0/tests/test_storage.py +68 -0
  46. agentmemdb-0.1.0/tests/test_tools.py +168 -0
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
5
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.0] - 2026-10-26
10
+
11
+ First public release.
12
+
13
+ ### Added
14
+
15
+ - 16 MCP tools to save, search, append, update, link and review memories
16
+ - SQLite FTS5 search with stemming, BM25 ranking, snippets and a substring fallback
17
+ - Duplicate warnings, automatic tags, threads, entities, expiry and edit history
18
+ - One database shared by every MCP client on the machine; each write records which client made it
19
+ - Optional JSON config for the database path, auto-tag rules and agent instructions, with clear errors for invalid values
20
+ - stdio and streamable HTTP transports; `--check` and `--version` flags
21
+ - Server name, version and icon reported to MCP clients
22
+
23
+ [Unreleased]: https://github.com/harsh-gulhane/agentmemdb/compare/v0.1.0...HEAD
24
+ [0.1.0]: https://github.com/harsh-gulhane/agentmemdb/releases/tag/v0.1.0
@@ -0,0 +1,72 @@
1
+ # Contributing
2
+
3
+ Thanks for your interest in agentmemdb. Bug reports, ideas and pull requests are welcome.
4
+
5
+ ## Development setup
6
+
7
+ You need [uv](https://docs.astral.sh/uv/) and `make`.
8
+
9
+ ```sh
10
+ git clone https://github.com/harsh-gulhane/agentmemdb && cd agentmemdb
11
+ make install # creates .venv with an editable install and the dev tools
12
+ make check # lint, type-check and test: the same checks CI runs
13
+ ```
14
+
15
+ Without uv: `python -m venv .venv && .venv/bin/pip install -e . --group dev` (pip 25.1 or newer).
16
+
17
+ | Command | What it does |
18
+ |-|-|
19
+ | `make lint` | `ruff check` and `ruff format --check` |
20
+ | `make format` | Fix lint issues and format the code |
21
+ | `make typecheck` | `mypy` in strict mode |
22
+ | `make test` | `pytest`, including end-to-end stdio and HTTP sessions |
23
+ | `make cov` | Tests with a coverage report |
24
+ | `make build` | Build the sdist and wheel and validate them with `twine check` |
25
+
26
+ Optional: `uv tool install pre-commit && pre-commit install` runs ruff and basic file checks on every commit.
27
+
28
+ ## Project layout
29
+
30
+ ```text
31
+ src/agentmemdb/
32
+ cli.py command-line entry point
33
+ config.py settings from environment variables and the config file
34
+ server.py FastMCP app and the 16 tools
35
+ storage.py SQLite connections, schema, migrations
36
+ search.py FTS5 search, substring fallback, duplicate detection
37
+ models.py categories, importance levels, input validation
38
+ tests/ pytest suite; test_e2e.py drives real MCP sessions
39
+ scripts/ release.sh and update-formula.sh for maintainers
40
+ docs/ user documentation and logo assets
41
+ examples/ example config and memory policy prompt
42
+ ```
43
+
44
+ [docs/architecture.md](docs/architecture.md) explains how the pieces fit together.
45
+
46
+ ## Guidelines
47
+
48
+ - **Keep it small.** The only runtime dependency is `mcp`. Discuss new dependencies in an issue first.
49
+ - **Test every change.** Tests use a fresh temporary database per test and never touch your real memory database.
50
+ - **Keep tool contracts stable.** Tool names, parameters and response fields are an API that agents and instructions files depend on. Additive changes are fine; renames and removals need a deprecation path and a changelog entry.
51
+ - **Schema changes need a migration.** Bump `SCHEMA_VERSION` in `storage.py`, add an idempotent migration step, and add a test that upgrades a database from the previous version.
52
+ - **Tool docstrings are prompts.** Agents read them to decide which tool to call, so keep them accurate and concise.
53
+
54
+ ## Pull requests
55
+
56
+ 1. Branch from `main`.
57
+ 2. Make the change with tests, and run `make check`.
58
+ 3. Add a line under **Unreleased** in [CHANGELOG.md](CHANGELOG.md) for user-visible changes.
59
+ 4. Use short, imperative commit messages, e.g. `Add tag filter to search_memory`.
60
+ 5. Open the pull request and describe what changed and why.
61
+
62
+ ## Releasing
63
+
64
+ Maintainers only. Releases are published from GitHub Actions with PyPI trusted publishing, so no PyPI token is stored anywhere.
65
+
66
+ 1. Set `__version__` in `src/agentmemdb/__init__.py`, move the **Unreleased** changelog entries under `## [x.y.z] - <date>`, and merge to `main`.
67
+ 2. On an up-to-date `main`, run `scripts/release.sh x.y.z`. It:
68
+ - tags `vx.y.z` and pushes the tag;
69
+ - waits for the [release workflow](.github/workflows/release.yml), which tests, builds, uploads to PyPI and creates the GitHub release with the changelog notes;
70
+ - runs `scripts/update-formula.sh`, which points the Homebrew formula in [harsh-gulhane/homebrew-tap](https://github.com/harsh-gulhane/homebrew-tap) at the new version, refreshes its Python resources, installs and tests it, and pushes.
71
+
72
+ Dependabot opens weekly pull requests for new versions of Python packages, GitHub Actions and pre-commit hooks; CI must pass before merging them.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Harsh Gulhane
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ include CHANGELOG.md CONTRIBUTING.md SECURITY.md
2
+ graft docs
3
+ graft examples
4
+ graft tests
5
+ global-exclude *.py[cod] __pycache__
6
+ exclude docs/assets/social-preview.png
@@ -0,0 +1,163 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentmemdb
3
+ Version: 0.1.0
4
+ Summary: Local-first, shared long-term memory for AI agents: one SQLite database for Claude Code, omp and any MCP client
5
+ Author: Harsh Gulhane
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/harsh-gulhane/agentmemdb
8
+ Project-URL: Documentation, https://github.com/harsh-gulhane/agentmemdb/tree/main/docs
9
+ Project-URL: Source, https://github.com/harsh-gulhane/agentmemdb
10
+ Project-URL: Issues, https://github.com/harsh-gulhane/agentmemdb/issues
11
+ Project-URL: Changelog, https://github.com/harsh-gulhane/agentmemdb/blob/main/CHANGELOG.md
12
+ Keywords: mcp,mcp-server,ai-memory,agent-memory,sqlite,local-first,claude-code,llm
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: MacOS
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
+ Classifier: Programming Language :: Python :: 3.15
26
+ Classifier: Topic :: Database
27
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
28
+ Classifier: Typing :: Typed
29
+ Requires-Python: >=3.10
30
+ Description-Content-Type: text/markdown
31
+ License-File: LICENSE
32
+ Requires-Dist: mcp<2,>=1.26
33
+ Dynamic: license-file
34
+
35
+ <p align="center">
36
+ <picture>
37
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/harsh-gulhane/agentmemdb/main/docs/assets/logo-wordmark-dark.svg">
38
+ <img alt="agentmemdb" src="https://raw.githubusercontent.com/harsh-gulhane/agentmemdb/main/docs/assets/logo-wordmark-light.svg" width="420">
39
+ </picture>
40
+ </p>
41
+
42
+ <p align="center">
43
+ <strong>Local-first, shared long-term memory for AI agents.</strong><br>
44
+ One SQLite database, served over MCP, so Claude Code, omp and every other agent on your machine remember the same things.
45
+ </p>
46
+
47
+ <p align="center">
48
+ <a href="https://github.com/harsh-gulhane/agentmemdb/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/harsh-gulhane/agentmemdb/actions/workflows/ci.yml/badge.svg"></a>
49
+ <img alt="Python 3.10+" src="https://img.shields.io/badge/python-3.10%2B-3776AB?logo=python&logoColor=white">
50
+ <img alt="MCP server" src="https://img.shields.io/badge/MCP-server-7C3AED">
51
+ <a href="https://github.com/harsh-gulhane/agentmemdb/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue"></a>
52
+ </p>
53
+
54
+ <p align="center">
55
+ <a href="https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/getting-started.md">Getting started</a> ·
56
+ <a href="https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/examples.md">Examples</a> ·
57
+ <a href="https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/configuration.md">Configuration</a> ·
58
+ <a href="https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/tools.md">Tools</a> ·
59
+ <a href="https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/architecture.md">Architecture</a>
60
+ </p>
61
+
62
+ ---
63
+
64
+ AI agents forget everything when a session ends, and different agents never see what the others learned. agentmemdb gives them one long-term memory: a local SQLite file, exposed as 16 MCP tools, that every agent on your machine reads and writes.
65
+
66
+ - **Shared.** What Claude Code saves in the morning, omp can recall in the afternoon. Every write records which agent made it.
67
+ - **Local.** One file on your machine. No cloud service, no API keys, no embedding model, no telemetry.
68
+ - **Cheap to recall.** Ranked full-text search returns short snippets instead of whole memories, so lookups use few tokens.
69
+ - **Safe with many agents.** Concurrent readers and writers, and a failed call can never leave the database locked.
70
+
71
+ ## See it in action
72
+
73
+ ```text
74
+ You → Claude Code We're moving billing-api from MySQL to Postgres 17 for row-level security. Remember that.
75
+
76
+ save_memory {"topic": "billing-api: move from MySQL to Postgres 17", "category": "decision", "importance": "high", …}
77
+ ← {"status": "saved", "id": 1, "tags": "billing,database", "auto_tags_added": ["database"]}
78
+
79
+ You → omp (next day) Why are we moving billing to Postgres?
80
+
81
+ search_memory {"query": "why are we moving billing to postgres"}
82
+ ← {"count": 1, "results": [{"id": 1, "topic": "billing-api: move from MySQL to Postgres 17",
83
+ "snippet": "…we need row-level security to isolate merchants, which MySQL does not offer…"}]}
84
+ ```
85
+
86
+ The [examples](https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/examples.md) walk through the full session: appending from a second agent, attribution, duplicate warnings, threads and entities, with real responses.
87
+
88
+ ## Quick start
89
+
90
+ Install it with any of these (macOS or Linux, Python 3.10+):
91
+
92
+ ```sh
93
+ brew install harsh-gulhane/tap/agentmemdb # Homebrew
94
+ pipx install agentmemdb # or: pip install agentmemdb
95
+ uvx agentmemdb --check # or run it without installing, with uv
96
+ ```
97
+
98
+ `agentmemdb --check` shows where the database and config will live. Then connect your agents, using the server name `memory` everywhere so tool names match across clients (with uv, replace `agentmemdb` with `uvx agentmemdb`):
99
+
100
+ ```sh
101
+ # Claude Code
102
+ claude mcp add memory -s user -- agentmemdb
103
+ ```
104
+
105
+ ```jsonc
106
+ // omp: ~/.omp/agent/mcp.json
107
+ { "mcpServers": { "memory": { "type": "stdio", "command": "agentmemdb" } } }
108
+ ```
109
+
110
+ Claude Desktop, Cursor, VS Code, Codex and HTTP setups are in [getting started](https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/getting-started.md). To have agents save and search without being asked, add the [memory policy prompt](https://github.com/harsh-gulhane/agentmemdb/blob/main/examples/memory-policy.md) to your `CLAUDE.md` or `AGENTS.md`.
111
+
112
+ ## Features
113
+
114
+ - **Relevance search.** SQLite FTS5 with stemming and BM25 ranking, where topic and tag matches rank highest. Handles IDs and names like `OPS-2406`, `PR #3056` and `example.com`, plain questions, and partial words.
115
+ - **Structured memories.** Categories, importance levels, tags, threads, entities (people, services, repos, tickets) and expiry dates.
116
+ - **Automatic tags.** Regex rules in the config tag matching memories, e.g. anything mentioning Postgres or MySQL gets `database`.
117
+ - **Safe edits.** Duplicate warnings on save, append mode, and an edit history that keeps replaced content.
118
+ - **One policy for every agent.** Instructions in the config file reach every connected client's system prompt.
119
+ - **stdio or HTTP.** One process per client, or one shared server over streamable HTTP on localhost.
120
+
121
+ ## Tools
122
+
123
+ | Area | Tools |
124
+ |-|-|
125
+ | Save and edit | `save_memory`, `append_memory`, `update_memory`, `delete_memory` |
126
+ | Search and read | `search_memory`, `list_memories`, `get_memory`, `get_memory_history` |
127
+ | Entities | `find_by_entity`, `list_entities` |
128
+ | Threads and timeline | `get_thread`, `list_threads`, `get_daily_summary` |
129
+ | Maintenance | `find_duplicates`, `cleanup_expired`, `get_stats` |
130
+
131
+ Parameters and behaviour: [tool reference](https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/tools.md).
132
+
133
+ ## Configuration
134
+
135
+ Optional. `~/.config/agentmemdb/config.json`:
136
+
137
+ ```json
138
+ {
139
+ "db_path": "~/.local/share/agentmemdb/memory.db",
140
+ "auto_tags": { "database": "postgres|mysql|sqlite", "incident": "incident|outage" },
141
+ "instructions": "Search memory before answering questions about past work."
142
+ }
143
+ ```
144
+
145
+ Environment variables, path resolution, sharing and backups: [configuration](https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/configuration.md).
146
+
147
+ ## Development
148
+
149
+ ```sh
150
+ git clone https://github.com/harsh-gulhane/agentmemdb && cd agentmemdb
151
+ make install # uv sync: editable install plus dev tools
152
+ make check # ruff, mypy --strict, pytest
153
+ ```
154
+
155
+ See [CONTRIBUTING.md](https://github.com/harsh-gulhane/agentmemdb/blob/main/CONTRIBUTING.md) for the project layout and workflow.
156
+
157
+ ## Security
158
+
159
+ agentmemdb stores memories unencrypted in a local file and makes no network calls. Read [SECURITY.md](https://github.com/harsh-gulhane/agentmemdb/blob/main/SECURITY.md) for the security model, and report vulnerabilities privately through GitHub security advisories.
160
+
161
+ ## License
162
+
163
+ [MIT](https://github.com/harsh-gulhane/agentmemdb/blob/main/LICENSE) © Harsh Gulhane
@@ -0,0 +1,129 @@
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/harsh-gulhane/agentmemdb/main/docs/assets/logo-wordmark-dark.svg">
4
+ <img alt="agentmemdb" src="https://raw.githubusercontent.com/harsh-gulhane/agentmemdb/main/docs/assets/logo-wordmark-light.svg" width="420">
5
+ </picture>
6
+ </p>
7
+
8
+ <p align="center">
9
+ <strong>Local-first, shared long-term memory for AI agents.</strong><br>
10
+ One SQLite database, served over MCP, so Claude Code, omp and every other agent on your machine remember the same things.
11
+ </p>
12
+
13
+ <p align="center">
14
+ <a href="https://github.com/harsh-gulhane/agentmemdb/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/harsh-gulhane/agentmemdb/actions/workflows/ci.yml/badge.svg"></a>
15
+ <img alt="Python 3.10+" src="https://img.shields.io/badge/python-3.10%2B-3776AB?logo=python&logoColor=white">
16
+ <img alt="MCP server" src="https://img.shields.io/badge/MCP-server-7C3AED">
17
+ <a href="https://github.com/harsh-gulhane/agentmemdb/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue"></a>
18
+ </p>
19
+
20
+ <p align="center">
21
+ <a href="https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/getting-started.md">Getting started</a> ·
22
+ <a href="https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/examples.md">Examples</a> ·
23
+ <a href="https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/configuration.md">Configuration</a> ·
24
+ <a href="https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/tools.md">Tools</a> ·
25
+ <a href="https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/architecture.md">Architecture</a>
26
+ </p>
27
+
28
+ ---
29
+
30
+ AI agents forget everything when a session ends, and different agents never see what the others learned. agentmemdb gives them one long-term memory: a local SQLite file, exposed as 16 MCP tools, that every agent on your machine reads and writes.
31
+
32
+ - **Shared.** What Claude Code saves in the morning, omp can recall in the afternoon. Every write records which agent made it.
33
+ - **Local.** One file on your machine. No cloud service, no API keys, no embedding model, no telemetry.
34
+ - **Cheap to recall.** Ranked full-text search returns short snippets instead of whole memories, so lookups use few tokens.
35
+ - **Safe with many agents.** Concurrent readers and writers, and a failed call can never leave the database locked.
36
+
37
+ ## See it in action
38
+
39
+ ```text
40
+ You → Claude Code We're moving billing-api from MySQL to Postgres 17 for row-level security. Remember that.
41
+
42
+ save_memory {"topic": "billing-api: move from MySQL to Postgres 17", "category": "decision", "importance": "high", …}
43
+ ← {"status": "saved", "id": 1, "tags": "billing,database", "auto_tags_added": ["database"]}
44
+
45
+ You → omp (next day) Why are we moving billing to Postgres?
46
+
47
+ search_memory {"query": "why are we moving billing to postgres"}
48
+ ← {"count": 1, "results": [{"id": 1, "topic": "billing-api: move from MySQL to Postgres 17",
49
+ "snippet": "…we need row-level security to isolate merchants, which MySQL does not offer…"}]}
50
+ ```
51
+
52
+ The [examples](https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/examples.md) walk through the full session: appending from a second agent, attribution, duplicate warnings, threads and entities, with real responses.
53
+
54
+ ## Quick start
55
+
56
+ Install it with any of these (macOS or Linux, Python 3.10+):
57
+
58
+ ```sh
59
+ brew install harsh-gulhane/tap/agentmemdb # Homebrew
60
+ pipx install agentmemdb # or: pip install agentmemdb
61
+ uvx agentmemdb --check # or run it without installing, with uv
62
+ ```
63
+
64
+ `agentmemdb --check` shows where the database and config will live. Then connect your agents, using the server name `memory` everywhere so tool names match across clients (with uv, replace `agentmemdb` with `uvx agentmemdb`):
65
+
66
+ ```sh
67
+ # Claude Code
68
+ claude mcp add memory -s user -- agentmemdb
69
+ ```
70
+
71
+ ```jsonc
72
+ // omp: ~/.omp/agent/mcp.json
73
+ { "mcpServers": { "memory": { "type": "stdio", "command": "agentmemdb" } } }
74
+ ```
75
+
76
+ Claude Desktop, Cursor, VS Code, Codex and HTTP setups are in [getting started](https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/getting-started.md). To have agents save and search without being asked, add the [memory policy prompt](https://github.com/harsh-gulhane/agentmemdb/blob/main/examples/memory-policy.md) to your `CLAUDE.md` or `AGENTS.md`.
77
+
78
+ ## Features
79
+
80
+ - **Relevance search.** SQLite FTS5 with stemming and BM25 ranking, where topic and tag matches rank highest. Handles IDs and names like `OPS-2406`, `PR #3056` and `example.com`, plain questions, and partial words.
81
+ - **Structured memories.** Categories, importance levels, tags, threads, entities (people, services, repos, tickets) and expiry dates.
82
+ - **Automatic tags.** Regex rules in the config tag matching memories, e.g. anything mentioning Postgres or MySQL gets `database`.
83
+ - **Safe edits.** Duplicate warnings on save, append mode, and an edit history that keeps replaced content.
84
+ - **One policy for every agent.** Instructions in the config file reach every connected client's system prompt.
85
+ - **stdio or HTTP.** One process per client, or one shared server over streamable HTTP on localhost.
86
+
87
+ ## Tools
88
+
89
+ | Area | Tools |
90
+ |-|-|
91
+ | Save and edit | `save_memory`, `append_memory`, `update_memory`, `delete_memory` |
92
+ | Search and read | `search_memory`, `list_memories`, `get_memory`, `get_memory_history` |
93
+ | Entities | `find_by_entity`, `list_entities` |
94
+ | Threads and timeline | `get_thread`, `list_threads`, `get_daily_summary` |
95
+ | Maintenance | `find_duplicates`, `cleanup_expired`, `get_stats` |
96
+
97
+ Parameters and behaviour: [tool reference](https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/tools.md).
98
+
99
+ ## Configuration
100
+
101
+ Optional. `~/.config/agentmemdb/config.json`:
102
+
103
+ ```json
104
+ {
105
+ "db_path": "~/.local/share/agentmemdb/memory.db",
106
+ "auto_tags": { "database": "postgres|mysql|sqlite", "incident": "incident|outage" },
107
+ "instructions": "Search memory before answering questions about past work."
108
+ }
109
+ ```
110
+
111
+ Environment variables, path resolution, sharing and backups: [configuration](https://github.com/harsh-gulhane/agentmemdb/blob/main/docs/configuration.md).
112
+
113
+ ## Development
114
+
115
+ ```sh
116
+ git clone https://github.com/harsh-gulhane/agentmemdb && cd agentmemdb
117
+ make install # uv sync: editable install plus dev tools
118
+ make check # ruff, mypy --strict, pytest
119
+ ```
120
+
121
+ See [CONTRIBUTING.md](https://github.com/harsh-gulhane/agentmemdb/blob/main/CONTRIBUTING.md) for the project layout and workflow.
122
+
123
+ ## Security
124
+
125
+ agentmemdb stores memories unencrypted in a local file and makes no network calls. Read [SECURITY.md](https://github.com/harsh-gulhane/agentmemdb/blob/main/SECURITY.md) for the security model, and report vulnerabilities privately through GitHub security advisories.
126
+
127
+ ## License
128
+
129
+ [MIT](https://github.com/harsh-gulhane/agentmemdb/blob/main/LICENSE) © Harsh Gulhane
@@ -0,0 +1,23 @@
1
+ # Security policy
2
+
3
+ ## Supported versions
4
+
5
+ Security fixes are released for the latest minor version.
6
+
7
+ | Version | Supported |
8
+ |-|-|
9
+ | 0.1.x | Yes |
10
+
11
+ ## Reporting a vulnerability
12
+
13
+ Please do not open a public issue. Report it privately through [GitHub security advisories](https://github.com/harsh-gulhane/agentmemdb/security/advisories/new) with steps to reproduce and the affected version (`agentmemdb --version`). You should get a first response within a week.
14
+
15
+ ## Security model
16
+
17
+ agentmemdb is a local tool. Know these properties before you store anything sensitive:
18
+
19
+ - **No network calls.** The server never contacts external services and sends no telemetry.
20
+ - **Plaintext storage.** Memories are stored unencrypted in a SQLite file. A database directory that agentmemdb creates gets mode `0700`, so other users on the machine can't read it, but any process running as your user can. Use disk encryption, and don't store secrets such as passwords, tokens or private keys.
21
+ - **Every connected agent has full access.** Any MCP client you connect can read, change and delete every memory.
22
+ - **Treat memories as untrusted input.** Memories are text written by agents, which may have been influenced by the content they processed. An agent that recalls a memory should treat its content as data, not as instructions. This matters most when agents with different permissions share one database.
23
+ - **HTTP transport.** `--transport http` listens on 127.0.0.1 only, with DNS rebinding protection, but has no authentication: any local process can connect. Prefer stdio, and never expose the HTTP port beyond localhost.
@@ -0,0 +1,11 @@
1
+ # agentmemdb documentation
2
+
3
+ | Guide | What's in it |
4
+ |-|-|
5
+ | [Getting started](getting-started.md) | Install, connect Claude Code, omp, Claude Desktop, Cursor, VS Code, Codex or any MCP client, and verify |
6
+ | [Examples](examples.md) | Real prompts, tool calls and responses from two agents sharing one database |
7
+ | [Configuration](configuration.md) | Environment variables, the config file, sharing a database, backups |
8
+ | [Tool reference](tools.md) | All 16 tools and their parameters |
9
+ | [Architecture](architecture.md) | Package layout, data model, search, concurrency and migrations |
10
+
11
+ See also: [memory policy prompt](../examples/memory-policy.md), [contributing](../CONTRIBUTING.md), [security](../SECURITY.md), [changelog](../CHANGELOG.md).
@@ -0,0 +1,105 @@
1
+ # Architecture
2
+
3
+ ## Overview
4
+
5
+ ```mermaid
6
+ flowchart LR
7
+ subgraph clients [MCP clients]
8
+ cc[Claude Code]
9
+ omp[omp]
10
+ other[Cursor, Codex, VS Code, ...]
11
+ end
12
+ cc -- stdio --> p1[agentmemdb]
13
+ omp -- stdio --> p2[agentmemdb]
14
+ other -- "stdio or HTTP" --> p3[agentmemdb]
15
+ p1 --> db[("memory.db<br/>SQLite, WAL mode")]
16
+ p2 --> db
17
+ p3 --> db
18
+ ```
19
+
20
+ Each MCP client normally starts its own agentmemdb process over stdio. The processes hold no state of their own: everything lives in one SQLite file, so a memory saved through one client is visible to every other client immediately. SQLite's WAL mode lets them read and write the file concurrently.
21
+
22
+ ## Package layout
23
+
24
+ | Module | Responsibility |
25
+ |-|-|
26
+ | `cli.py` | Command-line entry point: `--transport`, `--port`, `--check`, `--version`. Validates the config before starting. |
27
+ | `config.py` | Resolves the database and config paths from environment variables and the config file; compiles auto-tag rules; builds the server instructions. |
28
+ | `server.py` | The FastMCP application and its 16 tools. Each tool runs inside a wrapper that turns `ToolError` into `{"error": ...}` and always rolls back and closes its connections. |
29
+ | `storage.py` | `Store` (tracked SQLite connections), the schema, and migrations. |
30
+ | `search.py` | FTS5 query building, BM25-ranked search with a substring fallback, duplicate detection. |
31
+ | `models.py` | Categories, importance levels, input validation, timestamps. |
32
+
33
+ ## Data model
34
+
35
+ ```mermaid
36
+ erDiagram
37
+ memories ||--o{ entities : "is linked to"
38
+ memories ||--o{ memory_history : "records changes in"
39
+ memories {
40
+ int id PK
41
+ text topic
42
+ text content
43
+ text category
44
+ text tags "comma-separated"
45
+ text importance
46
+ text source "client that saved it"
47
+ text thread_id
48
+ text expires_at
49
+ text created_at
50
+ text updated_at
51
+ }
52
+ entities {
53
+ int id PK
54
+ int memory_id FK
55
+ text entity_type "lowercased"
56
+ text entity_value "lowercased"
57
+ }
58
+ memory_history {
59
+ int id PK
60
+ int memory_id FK
61
+ text action "created, appended, updated"
62
+ text content_snippet
63
+ text previous_content "text replaced by update_memory"
64
+ text created_at
65
+ }
66
+ ```
67
+
68
+ `memories_fts` is an FTS5 external-content index over `topic`, `content` and `tags` with the `porter unicode61` tokenizer (stemming, Unicode-aware). Triggers keep it in sync with `memories`. Deleting a memory removes its entities and history through foreign keys.
69
+
70
+ ## Search
71
+
72
+ `search_memory` runs these steps and returns the results of the first one that matches:
73
+
74
+ 1. The query as typed, so FTS5 syntax works (`tags:aws`, `datadog OR sentry`, `"exact phrase"`).
75
+ 2. Every term, each quoted (`"PR" "#3056"`), so punctuation in IDs, hostnames and hyphenated names can't break the query.
76
+ 3. Any term, which makes plain questions like "why are we moving billing to postgres" work.
77
+ 4. Substring matching on topic, content and tags, for partial words FTS can't match (`gres` in `postgres`), ranked by how many query words match.
78
+
79
+ FTS results are ranked by BM25 with column weights topic 10, tags 5, content 1. Expiry and the category and importance filters are applied in SQL before the limit, through an `is_expired()` SQL function. Each result includes a snippet of about 32 tokens instead of the full content; `full_content=true` or `get_memory` returns everything.
80
+
81
+ ## Duplicate detection
82
+
83
+ `save_memory` warns about likely duplicates before inserting. Candidates are memories with the same topic (case-insensitive), or topics that share at least two significant words covering 60% of the shorter topic. Stop words, words under three characters and numbers of up to four digits (years, small counts) don't count. `find_duplicates` uses the same rule to group similar memories across the whole database.
84
+
85
+ ## Concurrency and reliability
86
+
87
+ - **WAL mode** lets readers and writers in different processes work at the same time. Writers wait up to 10 seconds for the lock (`busy_timeout`).
88
+ - **No leaked locks.** Every tool call opens its own connection, and a wrapper rolls back and closes every connection the call opened, even when it raises. A failed call can't leave the database locked for other agents.
89
+ - **Validate before writing.** Inputs (category, importance, expiry, entities) are checked before the first write, so invalid calls change nothing.
90
+ - **Private by default.** A database directory that agentmemdb creates gets mode `0700`.
91
+
92
+ ## Schema migrations
93
+
94
+ The schema version is stored in `PRAGMA user_version`. On the first connection, agentmemdb creates any missing tables, then applies pending migrations inside a single `BEGIN IMMEDIATE` transaction, so concurrent first starts can't both migrate. Migrations are idempotent and one-way.
95
+
96
+ | Version | Change |
97
+ |-|-|
98
+ | 1 | Porter stemming in the FTS index (rebuilt), `memory_history.previous_content`, lowercased and deduplicated entities |
99
+
100
+ ## Design choices
101
+
102
+ - **SQLite and FTS5 instead of embeddings.** No model to download, no API key, no vector store, and results are explainable. Agents phrase their own queries and can retry with different words, which suits keyword search well.
103
+ - **A single file.** Easy to back up, inspect with `sqlite3`, or move between machines.
104
+ - **Snippets by default.** Search responses stay small, so recall costs few tokens.
105
+ - **Client attribution from the MCP handshake.** `source` defaults to the client name the client reports, so attribution works without configuration.
@@ -0,0 +1,35 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 456 96" width="456" height="96" role="img" aria-label="agentmemdb">
2
+ <g transform="scale(0.375)">
3
+ <defs>
4
+ <linearGradient id="amdb-bg" x1="0" y1="0" x2="1" y2="1">
5
+ <stop offset="0" stop-color="#4F46E5"/>
6
+ <stop offset="1" stop-color="#9333EA"/>
7
+ </linearGradient>
8
+ <linearGradient id="amdb-disc" x1="0" y1="0" x2="1" y2="0">
9
+ <stop offset="0" stop-color="#FFFFFF"/>
10
+ <stop offset="1" stop-color="#E0E7FF"/>
11
+ </linearGradient>
12
+ <clipPath id="amdb-back"><rect width="256" height="128"/></clipPath>
13
+ <clipPath id="amdb-front"><rect y="128" width="256" height="128"/></clipPath>
14
+ </defs>
15
+ <rect width="256" height="256" rx="60" fill="url(#amdb-bg)"/>
16
+ <g transform="rotate(-18 128 128)" fill="none" stroke="#FBBF24" stroke-width="7">
17
+ <ellipse cx="128" cy="128" rx="104" ry="32" clip-path="url(#amdb-back)"/>
18
+ </g>
19
+ <g fill="url(#amdb-disc)">
20
+ <ellipse cx="128" cy="72" rx="56" ry="19" fill="#FFFFFF"/>
21
+ <path d="M72 82A56 19 0 0 0 184 82V111A56 19 0 0 1 72 111Z"/>
22
+ <path d="M72 121A56 19 0 0 0 184 121V150A56 19 0 0 1 72 150Z"/>
23
+ <path d="M72 160A56 19 0 0 0 184 160V189A56 19 0 0 1 72 189Z"/>
24
+ </g>
25
+ <g transform="rotate(-18 128 128)" fill="#FBBF24">
26
+ <ellipse cx="128" cy="128" rx="104" ry="32" fill="none" stroke="#FBBF24" stroke-width="7" clip-path="url(#amdb-front)"/>
27
+ <circle cx="24" cy="128" r="13"/>
28
+ <circle cx="232" cy="128" r="13"/>
29
+ <circle cx="150" cy="159" r="13"/>
30
+ </g>
31
+ </g>
32
+ <path fill="#F8FAFC" d="M129.26 68.91Q126.49 68.91 124.33 67.99Q122.17 67.07 120.93 65.21Q119.69 63.35 119.69 60.58Q119.69 58.23 120.56 56.67Q121.43 55.1 122.94 54.13Q124.46 53.17 126.42 52.67Q128.39 52.17 130.55 51.99Q133.11 51.72 134.61 51.48Q136.11 51.25 136.77 50.8Q137.43 50.35 137.43 49.45V49.27Q137.43 48.24 136.88 47.46Q136.33 46.69 135.31 46.24Q134.29 45.79 132.87 45.79Q131.45 45.79 130.35 46.24Q129.26 46.69 128.63 47.5Q127.99 48.32 127.89 49.4H120.58Q120.77 46.53 122.28 44.42Q123.8 42.31 126.54 41.16Q129.29 40.02 133.11 40.02Q135.96 40.02 138.2 40.66Q140.44 41.31 141.98 42.55Q143.52 43.79 144.31 45.55Q145.11 47.32 145.11 49.56V68.44H137.51V64.51H137.41Q136.67 65.88 135.59 66.86Q134.51 67.83 132.95 68.37Q131.39 68.91 129.26 68.91ZM131.42 63.51Q133.29 63.51 134.65 62.82Q136.01 62.14 136.75 60.95Q137.49 59.76 137.49 58.26V55.47Q137.14 55.65 136.59 55.82Q136.04 55.99 135.3 56.14Q134.56 56.28 133.69 56.44Q132.82 56.6 131.9 56.73Q130.55 56.94 129.47 57.38Q128.39 57.81 127.76 58.54Q127.12 59.26 127.12 60.37Q127.12 61.35 127.65 62.06Q128.18 62.77 129.15 63.14Q130.13 63.51 131.42 63.51ZM163.75 79.83Q159.79 79.83 157.04 78.71Q154.28 77.59 152.71 75.56Q151.14 73.53 150.75 70.81H158.24Q158.53 71.87 159.28 72.61Q160.03 73.34 161.16 73.73Q162.3 74.11 163.75 74.11Q166.59 74.11 168.14 72.55Q169.68 71 169.68 67.99V63.72H169.65Q168.84 65.35 167.61 66.41Q166.38 67.46 164.81 67.96Q163.25 68.47 161.43 68.47Q157.79 68.47 155.07 66.65Q152.36 64.83 150.87 61.64Q149.38 58.45 149.38 54.31Q149.38 50.11 150.89 46.88Q152.41 43.65 155.11 41.83Q157.81 40.02 161.37 40.02Q163.19 40.02 164.74 40.52Q166.28 41.02 167.53 42.05Q168.78 43.07 169.65 44.63H169.68V40.6H177.35V67.36Q177.35 71.76 175.64 74.52Q173.92 77.27 170.85 78.55Q167.78 79.83 163.75 79.83ZM163.43 62.24Q165.41 62.24 166.87 61.25Q168.33 60.27 169.15 58.45Q169.97 56.63 169.97 54.2Q169.97 51.77 169.15 49.97Q168.33 48.16 166.87 47.17Q165.41 46.19 163.43 46.19Q161.56 46.19 160.16 47.12Q158.76 48.06 157.99 49.85Q157.21 51.64 157.21 54.2Q157.21 56.76 157.99 58.55Q158.76 60.34 160.16 61.29Q161.56 62.24 163.43 62.24ZM195.57 69.07Q191.35 69.07 188.23 67.21Q185.1 65.35 183.38 62.06Q181.65 58.76 181.65 54.54Q181.65 50.27 183.4 46.99Q185.16 43.71 188.24 41.83Q191.33 39.96 195.31 39.96Q198.39 39.96 200.9 41Q203.4 42.05 205.22 43.98Q207.04 45.92 208.03 48.56Q209.02 51.19 209.02 54.39V56.47H184.42V51.51H205.28L201.77 52.7Q201.77 50.59 201 49.06Q200.24 47.53 198.83 46.7Q197.42 45.87 195.47 45.87Q193.54 45.87 192.14 46.7Q190.75 47.53 189.98 49.06Q189.22 50.59 189.22 52.7V56.07Q189.22 58.23 190 59.86Q190.77 61.48 192.25 62.36Q193.73 63.24 195.81 63.24Q197.34 63.24 198.51 62.81Q199.69 62.37 200.49 61.57Q201.29 60.77 201.64 59.69H208.73Q208.23 62.45 206.38 64.56Q204.54 66.67 201.74 67.87Q198.95 69.07 195.57 69.07ZM220.96 52.96V68.44H213.19V40.6H220.83V47.85H219.51Q220.83 44.15 223.28 42.08Q225.74 40.02 229.53 40.02Q232.51 40.02 234.7 41.29Q236.89 42.57 238.09 45.02Q239.29 47.48 239.29 51.01V68.44H231.54V52.43Q231.54 49.61 230.21 48.16Q228.87 46.71 226.42 46.71Q224.81 46.71 223.57 47.37Q222.33 48.03 221.65 49.42Q220.96 50.8 220.96 52.96ZM260.8 40.6V46.69H242.53V40.6ZM247.33 33H255.08V59.84Q255.08 61.24 255.66 61.79Q256.24 62.35 257.83 62.35Q258.48 62.35 259.39 62.35Q260.3 62.35 260.8 62.35V68.44Q260.09 68.44 258.83 68.44Q257.56 68.44 256.27 68.44Q251.68 68.44 249.51 66.65Q247.33 64.85 247.33 61.06Z"/>
33
+ <path fill="#A78BFA" d="M264.71 68.44V40.6H272.2V46.87H271.72Q272.46 44.55 273.8 43.03Q275.15 41.52 276.92 40.77Q278.68 40.02 280.63 40.02Q283.82 40.02 286.17 41.85Q288.52 43.68 289.02 46.87H288.2Q288.73 44.73 290.07 43.21Q291.42 41.68 293.35 40.85Q295.29 40.02 297.56 40.02Q300.25 40.02 302.37 41.18Q304.5 42.34 305.71 44.56Q306.92 46.79 306.92 49.98V68.44H299.17V51.41Q299.17 48.9 297.81 47.66Q296.45 46.42 294.45 46.42Q292.97 46.42 291.87 47.08Q290.76 47.74 290.16 48.91Q289.57 50.09 289.57 51.67V68.44H282.08V51.19Q282.08 49.03 280.79 47.73Q279.5 46.42 277.44 46.42Q276.07 46.42 274.95 47.07Q273.83 47.71 273.16 48.97Q272.49 50.22 272.49 52.01V68.44ZM325.14 69.07Q320.92 69.07 317.8 67.21Q314.67 65.35 312.95 62.06Q311.22 58.76 311.22 54.54Q311.22 50.27 312.97 46.99Q314.73 43.71 317.81 41.83Q320.9 39.96 324.88 39.96Q327.96 39.96 330.47 41Q332.97 42.05 334.79 43.98Q336.61 45.92 337.6 48.56Q338.59 51.19 338.59 54.39V56.47H313.99V51.51H334.84L331.34 52.7Q331.34 50.59 330.57 49.06Q329.81 47.53 328.4 46.7Q326.99 45.87 325.04 45.87Q323.11 45.87 321.71 46.7Q320.32 47.53 319.55 49.06Q318.79 50.59 318.79 52.7V56.07Q318.79 58.23 319.56 59.86Q320.34 61.48 321.82 62.36Q323.29 63.24 325.38 63.24Q326.91 63.24 328.08 62.81Q329.25 62.37 330.06 61.57Q330.86 60.77 331.21 59.69H338.3Q337.8 62.45 335.95 64.56Q334.11 66.67 331.31 67.87Q328.52 69.07 325.14 69.07ZM342.75 68.44V40.6H350.24V46.87H349.77Q350.51 44.55 351.85 43.03Q353.2 41.52 354.96 40.77Q356.73 40.02 358.68 40.02Q361.87 40.02 364.22 41.85Q366.56 43.68 367.06 46.87H366.25Q366.77 44.73 368.12 43.21Q369.46 41.68 371.4 40.85Q373.34 40.02 375.61 40.02Q378.3 40.02 380.42 41.18Q382.54 42.34 383.75 44.56Q384.97 46.79 384.97 49.98V68.44H377.22V51.41Q377.22 48.9 375.86 47.66Q374.5 46.42 372.5 46.42Q371.02 46.42 369.91 47.08Q368.8 47.74 368.21 48.91Q367.62 50.09 367.62 51.67V68.44H360.13V51.19Q360.13 49.03 358.84 47.73Q357.55 46.42 355.49 46.42Q354.12 46.42 353 47.07Q351.88 47.71 351.2 48.97Q350.53 50.22 350.53 52.01V68.44Z"/>
34
+ <path fill="#F8FAFC" d="M401.32 69.02Q397.68 69.02 394.96 67.2Q392.25 65.38 390.76 62.11Q389.27 58.84 389.27 54.49Q389.27 50.19 390.78 46.94Q392.3 43.68 395 41.85Q397.7 40.02 401.26 40.02Q403.08 40.02 404.61 40.5Q406.14 40.99 407.35 41.97Q408.57 42.94 409.46 44.44H409.49V29.15H417.24V68.44H409.59V64.17H409.57Q408.75 65.78 407.52 66.87Q406.3 67.96 404.72 68.49Q403.13 69.02 401.32 69.02ZM403.32 62.69Q405.3 62.69 406.76 61.68Q408.22 60.66 409.04 58.81Q409.86 56.97 409.86 54.49Q409.86 51.99 409.04 50.15Q408.22 48.32 406.76 47.31Q405.3 46.29 403.32 46.29Q401.45 46.29 400.05 47.25Q398.65 48.22 397.87 50.05Q397.1 51.88 397.1 54.49Q397.1 57.1 397.87 58.93Q398.65 60.77 400.05 61.73Q401.45 62.69 403.32 62.69ZM438.7 69.02Q436.88 69.02 435.3 68.49Q433.72 67.96 432.48 66.87Q431.24 65.78 430.45 64.17H430.42V68.44H422.75V29.15H430.53V44.44H430.56Q431.45 42.94 432.67 41.97Q433.88 40.99 435.42 40.5Q436.96 40.02 438.76 40.02Q442.32 40.02 445.02 41.85Q447.72 43.68 449.24 46.94Q450.75 50.19 450.75 54.49Q450.75 58.84 449.25 62.11Q447.75 65.38 445.06 67.2Q442.37 69.02 438.7 69.02ZM436.7 62.69Q438.6 62.69 439.98 61.73Q441.37 60.77 442.15 58.93Q442.92 57.1 442.92 54.49Q442.92 51.88 442.15 50.05Q441.37 48.22 439.98 47.25Q438.6 46.29 436.7 46.29Q434.75 46.29 433.26 47.31Q431.77 48.32 430.97 50.15Q430.16 51.99 430.16 54.49Q430.16 56.97 430.97 58.81Q431.77 60.66 433.26 61.68Q434.75 62.69 436.7 62.69Z"/>
35
+ </svg>