Skip to content

Commit 44635ac

Browse files
committed
Release 0.42.0 - Interface refactor: unified put() and find()
Unified remember()+update() into put(content, uri, id, summary, tags). Unified find()+find_similar()+query_fulltext() into find(query, similar_to, fulltext). Security: error log 0o600, binary stdin handling, tag validation on all paths. REST: unified POST /search, ValueError→400, include_hidden fixes. Protocol: KeeperProtocol fully aligned with Keeper and RemoteKeeper.
1 parent 61df576 commit 44635ac

24 files changed

Lines changed: 333 additions & 437 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ from keep import Keeper
125125
kp = Keeper()
126126

127127
# Index
128-
kp.update("file:///path/to/doc.md", tags={"project": "myapp"})
129-
kp.remember("Rate limit is 100 req/min", tags={"topic": "api"})
128+
kp.put(uri="file:///path/to/doc.md", tags={"project": "myapp"})
129+
kp.put("Rate limit is 100 req/min", tags={"topic": "api"})
130130

131131
# Search
132132
results = kp.find("rate limit", limit=5)

SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: keep
3-
version: 0.41.0
3+
version: 0.42.0
44
description: Reflective Memory
55
homepage: https://github.com/hughpyle/keep
66
runtime: python:3.12-slim

docs/ARCHITECTURE.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ The original document content is **not stored** — only the summary and embeddi
3131
┌─────────────────────────────────────────────────────────────┐
3232
│ API Layer (api.py) │
3333
│ - Keeper class │
34-
│ - High-level operations: update(), remember(), find()
34+
│ - High-level operations: put(), find(), get()
3535
│ - Version management: get_version(), list_versions() │
3636
└──────────────────┬──────────────────────────────────────────┘
3737
@@ -83,7 +83,7 @@ The original document content is **not stored** — only the summary and embeddi
8383

8484
## Data Flow
8585

86-
### Indexing: update(uri) or remember(content)
86+
### Indexing: put(uri=...) or put(content)
8787

8888
```
8989
URI or content
@@ -200,7 +200,7 @@ delete(id)
200200

201201
**5. Immutable Items**
202202
- `Item` is frozen dataclass
203-
- Updates via `update()` return new Item
203+
- Updates via `put()` return new Item
204204
- Prevents accidental mutation bugs
205205

206206
**6. System Tag Protection**
@@ -313,7 +313,7 @@ Generate text descriptions from media files, enriching metadata-only content.
313313
- **mlx**: Apple Silicon — vision (mlx-vlm) + audio transcription (mlx-whisper)
314314
- **ollama**: Local server — vision models only (llava, moondream, bakllava)
315315

316-
Media description runs in `Keeper.update()` between fetch and upsert. Descriptions are appended to the metadata content before embedding/summarization, making media files semantically searchable by their visual or audio content.
316+
Media description runs in `Keeper.put()` between fetch and upsert. Descriptions are appended to the metadata content before embedding/summarization, making media files semantically searchable by their visual or audio content.
317317

318318
Design points:
319319
- Only triggered for non-text content types (image/*, audio/*)
@@ -373,7 +373,7 @@ Design points:
373373
- Lazy loading prevents import-time crashes
374374

375375
**URI Fetch Failures**
376-
- `update()` raises `IOError` for unreachable URIs
376+
- `put()` raises `IOError` for unreachable URIs
377377
- Original error preserved in exception chain
378378

379379
**Invalid Config**

docs/OUTPUT.md

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@ meta/todo: # 5. Meta sections
1818
- %b7c8d9e0 update auth docs for new flow
1919
meta/learnings:
2020
- %f1a2b3c4 Token refresh needs clock sync
21-
prev: # 6. Version navigation
21+
parts: # 6. Parts (structural)
22+
- @P{1} OAuth2 Flow Design (§1, pp.1-7)
23+
- @P{2} Token Storage Strategy (§2, pp.8-13)
24+
- @P{3} Session Management (§3, pp.14-18)
25+
prev: # 7. Version navigation
2226
- @V{1} 2026-01-14 Previous version of this item...
2327
- @V{2} 2026-01-13 Older version...
2428
---
25-
I'll fix the auth bug by Friday # 7. Content
29+
I'll fix the auth bug by Friday # 8. Content
2630
```
2731

2832
## Sections
@@ -92,7 +96,22 @@ These are dynamically resolved — the same item shows different meta sections d
9296

9397
See [META-DOCS.md](META-DOCS.md) for how meta-docs work and how to create custom ones.
9498

95-
### 6. `prev:` / `next:` — Version navigation
99+
### 6. `parts:` — Structural decomposition
100+
101+
Sections of a document identified by `keep analyze`. Each line:
102+
103+
```
104+
- @P{N} Section summary...
105+
```
106+
107+
- **`@P{N}`** — part number (1-indexed). Use with `keep get "ID@P{1}"` to view a specific part.
108+
- Parts have their own tags, embeddings, and similar items — they appear independently in search results.
109+
- Only appears when a note has been analyzed. View all parts with `keep get ID --parts`.
110+
- Parts are the structural counterpart to versions: versions are temporal (`@V{N}`), parts are spatial (`@P{N}`).
111+
112+
See [KEEP-ANALYZE.md](KEEP-ANALYZE.md) for how to decompose documents into parts.
113+
114+
### 7. `prev:` / `next:` — Version navigation
96115

97116
Navigate through the item's version history.
98117

@@ -108,7 +127,7 @@ prev:
108127

109128
See [VERSIONING.md](VERSIONING.md) for full versioning details.
110129

111-
### 7. Content (after `---`)
130+
### 8. Content (after `---`)
112131

113132
The item's summary, below the closing `---`. For short content this is the full text; for long documents it's a generated summary.
114133

docs/PYTHON-API.md

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ from keep import Keeper
1818
kp = Keeper() # Uses ~/.keep/ by default
1919

2020
# Index documents
21-
kp.update("file:///path/to/doc.md", tags={"project": "myapp"})
22-
kp.update("https://example.com/page", tags={"topic": "reference"})
23-
kp.remember("Important insight about auth patterns")
21+
kp.put(uri="file:///path/to/doc.md", tags={"project": "myapp"})
22+
kp.put(uri="https://example.com/page", tags={"topic": "reference"})
23+
kp.put("Important insight about auth patterns")
2424

2525
# Search
2626
results = kp.find("authentication", limit=5)
@@ -59,38 +59,36 @@ kp = Keeper(store_path="/path/to/store")
5959

6060
```python
6161
# Index from URI (file:// or https://)
62-
kp.update(uri, tags={}, summary=None) → Item
62+
kp.put(uri=uri, tags={}, summary=None) → Item
6363

6464
# Index inline content
65-
kp.remember(content, summary=None, tags={}) → Item
65+
kp.put(content, tags={}, summary=None) → Item
6666

6767
# Notes:
68+
# - Exactly one of content or uri must be provided
6869
# - If summary provided, skips auto-summarization
69-
# - remember() uses content verbatim if short (≤max_summary_length)
70+
# - Inline content used verbatim if short (≤max_summary_length)
7071
# - User tags (domain, topic, etc.) provide context for summarization
7172
```
7273

7374
#### Search
7475

7576
```python
76-
# Semantic search
77-
kp.find(query, limit=10, since=None) → list[Item]
77+
# Semantic search (default)
78+
kp.find("auth", limit=10) → list[Item]
7879

79-
# Find similar to a document
80-
kp.find_similar(uri, limit=10, since=None) → list[Item]
80+
# Full-text search
81+
kp.find("auth", fulltext=True) → list[Item]
8182

82-
# Similar items using stored embedding
83-
kp.get_similar_for_display(id, limit=3) → list[Item]
83+
# Find similar to an existing note
84+
kp.find(similar_to="note-id", limit=10) → list[Item]
8485

8586
# Tag-based query
8687
kp.query_tag(key, value=None, since=None) → list[Item]
8788

88-
# Full-text search
89-
kp.query_fulltext(query, since=None) → list[Item]
90-
9189
# Time filtering (all search methods support since)
9290
kp.find("auth", since="P7D") # Last 7 days
93-
kp.find("auth", since="P1W") # Last week
91+
kp.find("auth", since="P1W") # Last week
9492
kp.find("auth", since="PT1H") # Last hour
9593
kp.find("auth", since="2026-01-15") # Since date
9694
```
@@ -192,7 +190,7 @@ When indexing, tags merge in priority order (later wins):
192190
1. Existing tags (from previous version)
193191
2. Config tags (from `[tags]` in keep.toml)
194192
3. Environment tags (from `KEEP_TAG_*` variables)
195-
4. User tags (passed to `update()`, `remember()`, or `tag()`)
193+
4. User tags (passed to `put()` or `tag()`)
196194

197195
### Tag Rules
198196

@@ -207,7 +205,7 @@ import os
207205
os.environ["KEEP_TAG_PROJECT"] = "myapp"
208206
os.environ["KEEP_TAG_OWNER"] = "alice"
209207

210-
kp.remember("note") # Auto-tagged with project=myapp, owner=alice
208+
kp.put("note") # Auto-tagged with project=myapp, owner=alice
211209
```
212210

213211
### Config Tags

docs/REFERENCE.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,13 @@ See [PYTHON-API.md](PYTHON-API.md) for complete Python API reference.
152152
```python
153153
from keep import Keeper
154154
kp = Keeper()
155-
kp.remember("note", tags={"project": "myapp"})
155+
kp.put("note", tags={"project": "myapp"})
156156
results = kp.find("authentication", limit=5)
157157
```
158158

159159
## When to Use
160-
- `put` / `update()` — when referencing any file/URL worth remembering
161-
- `put` / `remember()` — capture conversation insights, decisions, notes
160+
- `put` / `put(uri=...)` — when referencing any file/URL worth remembering
161+
- `put` / `put("text")` — capture conversation insights, decisions, notes
162162
- `find` — before searching filesystem; may already be indexed
163163
- `find --since` — filter to recent items when recency matters
164164

docs/SYSTEM-TAGS.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ These tags are actively set and maintained by the system.
5454

5555
**Set by:** `_record_to_item()` in `api.py`, from `accessed_at` column in `DocumentStore`
5656

57-
**Behavior:** Updated whenever the item is retrieved via `get()`, `find()`, `find_similar()`, or `query_fulltext()`. Distinct from `_updated` — reading an item updates `_accessed` but not `_updated`.
57+
**Behavior:** Updated whenever the item is retrieved via `get()` or `find()`. Distinct from `_updated` — reading an item updates `_accessed` but not `_updated`.
5858

5959
**Example:** `"2026-02-07T09:15:00.123456+00:00"`
6060

@@ -78,25 +78,25 @@ These tags are actively set and maintained by the system.
7878

7979
**Purpose:** MIME type of the document content.
8080

81-
**Set by:** `Keeper.update()` in `api.py` (only for URI-based documents)
81+
**Set by:** `Keeper.put()` in `api.py` (only for URI-based documents)
8282

8383
**Behavior:** Set if the document provider returns a content type.
8484

8585
**Example:** `"text/markdown"`, `"text/html"`, `"application/pdf"`, `"audio/mpeg"`, `"image/jpeg"`
8686

87-
**Note:** Not set for inline content (CLI: `keep put "text"`, API: `kp.remember()`).
87+
**Note:** Not set for inline content (CLI: `keep put "text"`, API: `kp.put("text")`).
8888

8989
---
9090

9191
### `_source`
9292

9393
**Purpose:** How the content was obtained.
9494

95-
**Set by:** `Keeper.update()` and `Keeper.remember()` in `api.py`
95+
**Set by:** `Keeper.put()` in `api.py`
9696

9797
**Values:**
98-
- `"uri"` - Content fetched from a URI (CLI: `keep put <uri>`, API: `kp.update()`)
99-
- `"inline"` - Inline content (CLI: `keep put "text"`, API: `kp.remember()`)
98+
- `"uri"` - Content fetched from a URI (CLI: `keep put <uri>`, API: `kp.put(uri=...)`)
99+
- `"inline"` - Inline content (CLI: `keep put "text"`, API: `kp.put("text")`)
100100

101101
**Usage:** Query with `kp.query_tag("_source", "inline")` to find remembered content.
102102

@@ -115,7 +115,7 @@ def filter_non_system_tags(tags: dict[str, str]) -> dict[str, str]:
115115
return {k: v for k, v in tags.items() if not k.startswith(SYSTEM_TAG_PREFIX)}
116116
```
117117

118-
This function is called before merging user-provided tags in `update()` (API), `remember()` (API), and `tag()` methods.
118+
This function is called before merging user-provided tags in `put()` and `tag()` methods.
119119

120120
## Tag Merge Order
121121

@@ -124,7 +124,7 @@ When indexing documents, tags are merged in this order (later wins on collision)
124124
1. **Existing tags** - Preserved from previous version
125125
2. **Config tags** - From `[tags]` section in `keep.toml`
126126
3. **Environment tags** - From `KEEP_TAG_*` variables
127-
4. **User tags** - Passed to `update()`, `remember()`, or `tag()`
127+
4. **User tags** - Passed to `put()` or `tag()`
128128
5. **System tags** - Added/updated by system (cannot be overridden)
129129

130130
## Querying by System Tags

keep/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from keep import Keeper
99
1010
kp = Keeper()
11-
kp.update("file:///path/to/document.md", source_tags={"project": "myproject"})
11+
kp.put(uri="file:///path/to/document.md", tags={"project": "myproject"})
1212
results = kp.find("something similar to this query")
1313
1414
CLI Usage:
@@ -37,7 +37,7 @@
3737
)
3838
from .types import Item, filter_non_system_tags, SYSTEM_TAG_PREFIX, INTERNAL_TAGS
3939

40-
__version__ = "0.41.0"
40+
__version__ = "0.42.0"
4141
__all__ = [
4242
"Keeper",
4343
"Item",

0 commit comments

Comments
 (0)