memclaw 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.
@@ -0,0 +1,9 @@
1
+ # Required for embeddings and image descriptions
2
+ OPENAI_API_KEY=your-openai-key
3
+
4
+ # Required for the Claude agent (interactive mode + /ask command)
5
+ ANTHROPIC_API_KEY=your-anthropic-key
6
+
7
+ # Telegram bot settings
8
+ TELEGRAM_BOT_TOKEN=your-telegram-bot-token
9
+ ALLOWED_USER_IDS=123456789,987654321
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Set up Python ${{ matrix.python-version }}
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+
24
+ - name: Install dependencies
25
+ run: pip install -e ".[dev]"
26
+
27
+ - name: Run tests
28
+ run: pytest
@@ -0,0 +1,19 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ id-token: write
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: "3.12"
17
+ - run: pip install build
18
+ - run: python -m build
19
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,35 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+
7
+ # Distribution / packaging
8
+ build/
9
+ dist/
10
+ *.egg-info/
11
+ *.egg
12
+
13
+ # Virtual environments
14
+ .env
15
+ .envrc
16
+ .venv
17
+ venv/
18
+
19
+ # Testing
20
+ .pytest_cache/
21
+ .coverage
22
+ htmlcov/
23
+
24
+ # IDEs
25
+ .idea/
26
+ .vscode/
27
+ .cursorignore
28
+ .cursorindexingignore
29
+
30
+ # Type checkers / linters
31
+ .mypy_cache/
32
+ .ruff_cache/
33
+
34
+ # Memclaw local data
35
+ .memclaw/
@@ -0,0 +1,38 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to a positive environment:
15
+
16
+ - Using welcoming and inclusive language
17
+ - Being respectful of differing viewpoints and experiences
18
+ - Gracefully accepting constructive criticism
19
+ - Focusing on what is best for the community
20
+ - Showing empathy towards other community members
21
+
22
+ Examples of unacceptable behavior:
23
+
24
+ - The use of sexualized language or imagery, and sexual attention or advances of any kind
25
+ - Trolling, insulting or derogatory comments, and personal or political attacks
26
+ - Public or private harassment
27
+ - Publishing others' private information without explicit permission
28
+ - Other conduct which could reasonably be considered inappropriate in a professional setting
29
+
30
+ ## Enforcement
31
+
32
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
33
+ reported to the project maintainers at emanuilo.jovanovic@hotmail.com. All
34
+ complaints will be reviewed and investigated promptly and fairly.
35
+
36
+ ## Attribution
37
+
38
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1.
@@ -0,0 +1,76 @@
1
+ # Contributing to Memclaw
2
+
3
+ Thanks for your interest in contributing! Here's how to get started.
4
+
5
+ ## Development Setup
6
+
7
+ ```bash
8
+ git clone https://github.com/emanuilo/memclaw.git
9
+ cd memclaw
10
+ python -m venv .venv
11
+ source .venv/bin/activate
12
+ pip install -e ".[dev]"
13
+ ```
14
+
15
+ Copy the environment template and fill in your keys:
16
+
17
+ ```bash
18
+ cp .env.example .env
19
+ ```
20
+
21
+ ## Running Tests
22
+
23
+ ```bash
24
+ pytest
25
+ ```
26
+
27
+ All tests should pass before submitting a PR. The test suite mocks external API calls, so no API keys are needed to run tests.
28
+
29
+ ## Code Style
30
+
31
+ - Follow PEP 8 conventions
32
+ - Use type hints for function signatures
33
+ - Keep functions focused and small
34
+ - Run `ruff check .` before committing
35
+
36
+ ## Making Changes
37
+
38
+ 1. Fork the repository
39
+ 2. Create a feature branch (`git checkout -b feature/my-feature`)
40
+ 3. Make your changes
41
+ 4. Add or update tests as needed
42
+ 5. Run the test suite (`pytest`)
43
+ 6. Run the linter (`ruff check .`)
44
+ 7. Commit with a clear message (`git commit -m 'feat: add my feature'`)
45
+ 8. Push to your fork (`git push origin feature/my-feature`)
46
+ 9. Open a Pull Request
47
+
48
+ ## Commit Messages
49
+
50
+ Use [Conventional Commits](https://www.conventionalcommits.org/) style:
51
+
52
+ - `feat:` new feature
53
+ - `fix:` bug fix
54
+ - `docs:` documentation only
55
+ - `test:` adding or updating tests
56
+ - `chore:` maintenance, dependencies, CI
57
+
58
+ ## Pull Requests
59
+
60
+ - Keep PRs focused on a single change
61
+ - Include tests for new functionality
62
+ - Update documentation if behavior changes
63
+ - Link related issues in the PR description
64
+
65
+ ## Reporting Bugs
66
+
67
+ Open an issue with:
68
+
69
+ - Steps to reproduce
70
+ - Expected vs actual behavior
71
+ - Python version and OS
72
+ - Relevant logs or error messages
73
+
74
+ ## Questions?
75
+
76
+ Open a [discussion](https://github.com/emanuilo/memclaw/issues) or reach out in an issue.
memclaw-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Memclaw Contributors
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.
memclaw-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,324 @@
1
+ Metadata-Version: 2.4
2
+ Name: memclaw
3
+ Version: 0.1.0
4
+ Summary: A lightweight, local-first personal memory assistant powered by AI
5
+ Project-URL: Repository, https://github.com/emanuilo/memclaw
6
+ Project-URL: Issues, https://github.com/emanuilo/memclaw/issues
7
+ Author-email: Emanuilo Jovanovic <emanuilo.jovanovic@hotmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: ai,assistant,memory,personal-knowledge,second-brain,vector-search
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: anthropic>=0.40.0
22
+ Requires-Dist: beautifulsoup4>=4.12.0
23
+ Requires-Dist: claude-agent-sdk>=0.1.0
24
+ Requires-Dist: click>=8.0.0
25
+ Requires-Dist: httpx>=0.27.0
26
+ Requires-Dist: loguru>=0.7.0
27
+ Requires-Dist: numpy>=1.24.0
28
+ Requires-Dist: openai>=1.0.0
29
+ Requires-Dist: python-telegram-bot>=21.0
30
+ Requires-Dist: rich>=13.0.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest-asyncio>=1.0.0; extra == 'dev'
33
+ Requires-Dist: pytest>=9.0.0; extra == 'dev'
34
+ Requires-Dist: ruff>=0.9.0; extra == 'dev'
35
+ Description-Content-Type: text/markdown
36
+
37
+ <div align="center">
38
+
39
+ # Memclaw
40
+
41
+ **Your personal memory vault, powered by AI.**
42
+
43
+ Store your thoughts. Save your images and links. Ask anything, anytime.
44
+
45
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
46
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
47
+ [![Claude Agent SDK](https://img.shields.io/badge/Claude-Agent_SDK-blueviolet.svg)](https://platform.claude.com/docs/en/agent-sdk/overview)
48
+ [![Telegram Bot](https://img.shields.io/badge/Telegram-Bot-26A5E4.svg)](https://core.telegram.org/bots)
49
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)
50
+
51
+ </div>
52
+
53
+ ---
54
+
55
+ Memclaw is a lightweight, local-first personal memory assistant. It stores your thoughts, notes, images, and links as **plain Markdown files** and makes them instantly searchable through **hybrid vector + keyword search**.
56
+
57
+ Think of it as your second brain — one that actually remembers.
58
+
59
+ ## Why Memclaw?
60
+
61
+ [OpenClaw](https://github.com/openclaw/openclaw) is great — but it connects to dozens of tools, reads your filesystem, runs shell commands, and does a hundred things you didn't ask for. That makes it slow, expensive, and a security surface you have to think about every time you use it.
62
+
63
+ Memclaw takes one slice of what OpenClaw does — **memory** — and does it really well, without the rest.
64
+
65
+ **Total recall.** Save a thought today, retrieve it six months later with a vague description. *"What was that restaurant Alex told me about?"* — Memclaw finds it. Hybrid vector + keyword search means you don't need to remember exact words.
66
+
67
+ **Visual memory.** Send an image and Memclaw generates an AI caption, indexes it, and stores it. Later, just ask *"that food recipe photo"* or *"the whiteboard from last sprint"* and it comes right back.
68
+
69
+ **Link memory.** Drop a link and Memclaw fetches the page, summarizes it, and indexes the content. Months later, ask *"that article about distributed databases"* and it surfaces the link with context — no bookmarking app needed.
70
+
71
+ **Sandboxed by design.** Memclaw only touches `~/.memclaw/`. No filesystem access, no shell commands, no path traversal. You don't need to trust it with your whole computer — it can't see it.
72
+
73
+ **Lightweight and cheap.** No Docker. No Postgres. No sprawling tool graph burning tokens. Just Python, SQLite, and two API keys. Fast responses, minimal cost.
74
+
75
+ ## Quick Start
76
+
77
+ ```bash
78
+ pip install memclaw
79
+ memclaw
80
+ ```
81
+
82
+ On first run, Memclaw will prompt you for your API keys and save them to `~/.memclaw/.env`. You can update them anytime with `memclaw configure`.
83
+
84
+ ## Telegram Bot
85
+
86
+ The main way to use Memclaw. Just talk to it naturally — no commands needed. Send text, photos, voice messages, or links. The agent figures out what to do: store it, search your memories, retrieve images, or just chat.
87
+
88
+ The bot shows a **typing indicator** while processing so you know it's working on your request.
89
+
90
+ ### Setup
91
+
92
+ 1. Create a bot via [@BotFather](https://t.me/BotFather) and copy the token.
93
+ 2. Get your Telegram user ID (e.g. via [@userinfobot](https://t.me/userinfobot)).
94
+ 3. Start the bot — on first run you'll be prompted for all keys:
95
+
96
+ ```bash
97
+ memclaw bot
98
+ ```
99
+
100
+ To update keys later: `memclaw configure`.
101
+
102
+ ### What it handles
103
+
104
+ | Message type | What happens |
105
+ |-------------|-------------|
106
+ | **Text** | Agent decides: store as memory, search existing memories, or both. Links are extracted, fetched, and summarized automatically. |
107
+ | **Photo** | AI-described via vision model, stored and indexed. Agent acknowledges and responds. File ID saved for later retrieval. |
108
+ | **Voice** | Transcribed via Whisper, stored as text. Agent responds to the content. Links extracted. |
109
+
110
+ ### Examples
111
+
112
+ ```
113
+ > Just had coffee with Alex. She's moving to Berlin for a role at Stripe.
114
+ Got it! I've saved that Alex is moving to Berlin for a new role at Stripe.
115
+
116
+ > Who is Alex?
117
+ Based on your memories, Alex is someone you had coffee with recently.
118
+ She's moving to Berlin for a new role at Stripe.
119
+
120
+ > Show me the whiteboard photo from last week
121
+ [sends the matching photo]
122
+ Here's the sprint planning whiteboard you saved last week.
123
+ ```
124
+
125
+ ## How It Works
126
+
127
+ ```mermaid
128
+ flowchart LR
129
+ You -->|text / images / links| Agent[Memclaw Agent]
130
+
131
+ subgraph sandbox ["~/.memclaw/"]
132
+ Agent -->|save| Tools1["memory_save<br>image_save<br>file_write"]
133
+ Tools1 --> Files["MEMORY.md<br>daily/*.md<br>AGENTS.md"]
134
+ Files --> DB[("SQLite<br>FTS5 + Vectors")]
135
+ DB --> Tools2["memory_search<br>image_search"]
136
+ Tools2 -->|results| Agent
137
+ end
138
+
139
+ Agent -->|response + images| You
140
+ ```
141
+
142
+ Memclaw draws inspiration from [OpenClaw](https://github.com/openclaw/openclaw)'s memory architecture and is built with the [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview).
143
+
144
+ ### Storage Layer
145
+
146
+ All memories are plain Markdown — human-readable, editable, and git-friendly.
147
+
148
+ | File | Purpose |
149
+ |------|---------|
150
+ | `~/.memclaw/MEMORY.md` | Curated long-term facts and preferences |
151
+ | `~/.memclaw/AGENTS.md` | Customizable agent instructions and user preferences |
152
+ | `~/.memclaw/memory/YYYY-MM-DD.md` | Timestamped daily entries |
153
+ | `~/.memclaw/memclaw.db` | SQLite index (vector embeddings + FTS5) |
154
+
155
+ ### Search Layer
156
+
157
+ Every memory is chunked, embedded, and indexed in SQLite. Retrieval combines two signals:
158
+
159
+ - **Vector search** (70% weight) — cosine similarity via OpenAI embeddings finds semantically related memories even when wording differs
160
+ - **Keyword search** (30% weight) — BM25 via SQLite FTS5 catches exact tokens, names, and identifiers
161
+ - **Temporal decay** — recent memories score higher (30-day half-life), MEMORY.md entries are evergreen
162
+ - **MMR deduplication** — removes near-duplicate results to keep search diverse
163
+
164
+ ### Agent Layer
165
+
166
+ Powered by Claude via the [Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview). The agent maintains a rolling 10-message-pair conversation history and decides when to **store** vs **search** based on your intent.
167
+
168
+ | Tool | What it does |
169
+ |------|-------------|
170
+ | `memory_save` | Writes a new entry to today's daily file or MEMORY.md |
171
+ | `memory_search` | Hybrid search across all indexed memories |
172
+ | `image_save` | Generates an AI description of an image and stores it |
173
+ | `image_search` | Retrieves previously stored images by description |
174
+ | `file_write` / `file_read` | Sandboxed file operations within `~/.memclaw/` |
175
+ | `update_instructions` | Appends user preferences to AGENTS.md |
176
+
177
+ ## Usage
178
+
179
+ ### Interactive Mode (default)
180
+
181
+ ```bash
182
+ memclaw
183
+ ```
184
+
185
+ Chat naturally:
186
+
187
+ ```
188
+ > Just had coffee with Alex. She's moving to Berlin next month for a new role at Stripe.
189
+ ✓ Memory saved
190
+
191
+ > Who is Alex?
192
+ Based on your memories, Alex is someone you had coffee with recently.
193
+ She's moving to Berlin for a new role at Stripe.
194
+
195
+ > /quit
196
+ ```
197
+
198
+ ### Direct Commands
199
+
200
+ These work without the Claude agent — only the OpenAI key is needed for embeddings.
201
+
202
+ ```bash
203
+ # Save a quick note
204
+ memclaw save "Meeting at 3pm with the design team about the rebrand"
205
+
206
+ # Search your memories
207
+ memclaw search "design team meetings"
208
+
209
+ # Consolidate daily files into MEMORY.md
210
+ memclaw consolidate
211
+
212
+ # Rebuild the search index
213
+ memclaw index
214
+
215
+ # Check your memory vault
216
+ memclaw status
217
+ ```
218
+
219
+ ### Saving Images
220
+
221
+ In interactive mode, tell the agent to save an image:
222
+
223
+ ```
224
+ > Save the image at ~/photos/whiteboard.jpg — it's our sprint planning board
225
+ ✓ Image saved: A whiteboard showing a sprint planning layout with colorful sticky notes...
226
+ ```
227
+
228
+ The image is described by an AI vision model and the description is stored and indexed like any other memory.
229
+
230
+ ## Configuration
231
+
232
+ On first run, `memclaw` or `memclaw bot` will launch an interactive setup wizard that saves your keys to `~/.memclaw/.env`. Run `memclaw configure` anytime to update them.
233
+
234
+ You can also set keys via environment variables or a `.env` in the current directory — these take the usual precedence over the saved config.
235
+
236
+ ```bash
237
+ memclaw --memory-dir ~/my-vault # override storage location
238
+ ```
239
+
240
+ ### API Keys
241
+
242
+ | Variable | Required | Description |
243
+ |----------|----------|-------------|
244
+ | `OPENAI_API_KEY` | Yes | Embeddings + image descriptions |
245
+ | `ANTHROPIC_API_KEY` | Yes | Powers the Claude agent |
246
+ | `TELEGRAM_BOT_TOKEN` | For Telegram bot | Your Telegram bot token |
247
+ | `ALLOWED_USER_IDS` | For Telegram bot | Comma-separated Telegram user IDs |
248
+
249
+ ### Directory Structure
250
+
251
+ ```
252
+ ~/.memclaw/
253
+ ├── MEMORY.md # Permanent / curated memories
254
+ ├── AGENTS.md # Agent instructions + user preferences
255
+ ├── memclaw.db # SQLite index (embeddings + FTS5)
256
+ └── memory/
257
+ ├── 2025-06-15.md # Daily notes
258
+ ├── 2025-06-16.md
259
+ └── ...
260
+ ```
261
+
262
+ ## Architecture
263
+
264
+ Inspired by [OpenClaw](https://github.com/openclaw/openclaw)'s approach to AI memory:
265
+
266
+ - **Markdown as source of truth** — all memories live as plain text you can read, edit, and version-control
267
+ - **SQLite for indexing** — zero-config database with FTS5 for keyword search and BLOBs for embeddings
268
+ - **NumPy for vectors** — cosine similarity computed in-memory, no native extensions required
269
+ - **Claude Agent SDK** — intelligent agent loop that autonomously decides how to handle your input
270
+ - **Chunking with overlap** — ~300-word chunks with 60-word overlap preserve context across boundaries
271
+ - **Auto-consolidation** — daily files are periodically distilled into MEMORY.md
272
+ - **Filesystem guardrail** — SDK-level callback blocks all file access outside `~/.memclaw/`
273
+ - **Embedding cache** — SHA-256 content hashing skips redundant API calls
274
+
275
+ For a deep dive into how memory storage, search, consolidation, and context injection work, see the [Memory Architecture](docs/memory-architecture.md) doc.
276
+
277
+ ## Using as a Library
278
+
279
+ ```python
280
+ import asyncio
281
+ from memclaw.config import MemclawConfig
282
+ from memclaw.store import MemoryStore
283
+ from memclaw.index import MemoryIndex
284
+ from memclaw.search import HybridSearch
285
+
286
+ async def main():
287
+ config = MemclawConfig()
288
+ store = MemoryStore(config)
289
+ index = MemoryIndex(config)
290
+ search = HybridSearch(config, index)
291
+
292
+ # Save a memory
293
+ path = store.save("The best pizza in town is at Mario's on 5th Ave")
294
+ await index.index_file(path)
295
+
296
+ # Search
297
+ results = await search.search("pizza recommendations")
298
+ for r in results:
299
+ print(f"{r.score:.2f}: {r.content[:80]}")
300
+
301
+ index.close()
302
+
303
+ asyncio.run(main())
304
+ ```
305
+
306
+ ## Contributing
307
+
308
+ Contributions are welcome! Please feel free to submit a Pull Request.
309
+
310
+ 1. Fork the repository
311
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
312
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
313
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
314
+ 5. Open a Pull Request
315
+
316
+ ## License
317
+
318
+ MIT — see [LICENSE](LICENSE) for details.
319
+
320
+ ## Acknowledgments
321
+
322
+ - [OpenClaw](https://github.com/openclaw/openclaw) for the memory architecture inspiration
323
+ - [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview) for the agent framework
324
+ - [SQLite FTS5](https://www.sqlite.org/fts5.html) for full-text search